home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Samples / SampleCode / VwrFrameWork ƒ / VwrFrameWork.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-14  |  148.9 KB  |  5,446 lines  |  [TEXT/CWIE]

  1. /*
  2.  * This is a viewer application shell
  3.  *
  4.  * Nick Thompson, nickt@apple.com
  5.  * send bug reports to devsupport@apple.com
  6.  *
  7.  * ©1995-7 Apple Computer Inc., All Rights Reserved.
  8.  *
  9.  * This is a sample app that was originally written for an article in Develop
  10.  * issue 29, but please note that it is really extended from the example 
  11.  * presented in that article.  
  12.  *
  13.  * I've extended it to be the "reference" app for supporting plug-in 
  14.  * renderers.  Along the way it became apparent that just sticking all the renderers
  15.  * into a popup menu, simply did not cut the mustard.  Here's why.  There is a 
  16.  * distinction between interactive (for example the apple interactive renderer)
  17.  * and non interactive renderers (such as the lightwork renderer).  Bear in mind
  18.  * that the interactivity of a renderer is often a tradeoff against speed.  In particular, 
  19.  * it makes no sense whatsoever to support interactivity with a non interactive
  20.  * renderer.
  21.  *
  22.  * This led me to the big change in the application.  I decided that if the 
  23.  * renderer was non-interactive, then it should draw into a new window, which
  24.  * the user could save as a pict, print, or whatever.  Bear in mind that this is
  25.  * not the only way to do this.  Another simpler way would be to let the user
  26.  * chose a non interactive renderer, and just render one into the window, then
  27.  * switch back to the non interactive renderer.  I saw a couple of problems with
  28.  * this approach for this particular application, in particular that if the 
  29.  * window received an update event (out of the users control) then the window 
  30.  * or worse - part of the window - would get redrawn with the "wrong" renderer.
  31.  *
  32.  * This remains a work in progress.  As sample code it is useful as an 
  33.  * illustration of how to use the viewer, and an illustration of how to use
  34.  * plug-in renderers.
  35.  *
  36.  * As usual this is a work in progress, which means use the code at your own risk!!  
  37.  *
  38.  * If you fix a bug, or add some functionality feel free to send me the change and
  39.  * I'll roll it in.
  40.  *
  41.  * 
  42.  *
  43.  * TO DO: drag and drop support for pict windows
  44.  *        saving and restoring print records to files.
  45.  */
  46.  
  47.  
  48. /*------------------------------------------------------------ */
  49.  
  50. #include <AppleEvents.h>
  51. #include <ColorPicker.h>
  52. #include <Devices.h>
  53. #include <Dialogs.h>
  54. #include <Diskinit.h>
  55. #include <Events.h>
  56. #include <Errors.h>
  57. #include <Fonts.h>
  58. #include <Gestalt.h>
  59. #include <LowMem.h>
  60. #include <Printing.h>
  61. #include <QDOffscreen.h>
  62. #include <QuickDraw.h>
  63. #include <Menus.h>
  64. #include <Scrap.h>
  65. #include <SegLoad.h>
  66. #include <StandardFile.h>
  67. #include <TextUtils.h>
  68. #include <Strings.h>
  69. #include <Windows.h>
  70.  
  71.  
  72. #include <ctype.h>
  73. #include <stdarg.h>
  74.  
  75. /* always include this before anything else when using the QuickDraw 3D library  */
  76. #include "QD3D.h"
  77.  
  78. /* viewer support  */
  79. #include "QD3DViewer.h"
  80.  
  81. /* this has the routines for renderer objects  */
  82. #include "QD3DRenderer.h"
  83.  
  84. /* this has the routines for view objects  */
  85. #include "QD3DView.h"
  86.  
  87. /* this header allows us to check for the viewer  */
  88. #include <CodeFragments.h>
  89.  
  90.  
  91. /*------------------------------------------------------------ */
  92.  
  93. /* convenience macros to peek at event records  */
  94.  
  95. #define     HiWrd(aLong)            (((aLong) >> 16) & 0xFFFF)
  96. #define     LoWrd(aLong)            ((aLong) & 0xFFFF)
  97.  
  98. #define     kMaxRendererCount        30
  99. #define        RETURN_KEY                 0x0D
  100. #define        ENTER_KEY                 0x03
  101. #define        ESCAPE                     0x1B
  102.  
  103. #define        kProgressBarDlogID        1028
  104. #define        kProgressBarPBItemID    2
  105.  
  106.  
  107. /*------------------------------------------------------------ */
  108.  
  109. /* constants  */
  110. const    short                kWindHeight = 350 ;            /* default theWindow height  */
  111. const    short                kWindWidth = 300 ;            /* default theWindow width  */
  112. const    short                kMaxHeight = 400 ;            /* max theWindow height  */
  113. const    short                kMaxWidth = 560 ;            /* max theWindow width  */
  114. const    SFTypeList            kTypeList = { '3DMF' } ;    /* file type we can open  */
  115. const    short                kNumTypes = 1 ;             /* num of file types we can recognise  */
  116.  
  117. const    short                kAppMenuBarID = 128 ;        /* resource ID for the application's menu bar  */
  118. const    short                kFatalAlert = 128 ;            /* res ID for error alert before we bail  */
  119. const    short                 kErrorAlertStrings = 128 ;    /* res ID for alert strs  */
  120. const    short                kAboutDialogID = 129;        /* ID for the about box dialog  */
  121. const    short                kFinalRenderDialogID = 130;    /* ID for the final quality render dialog  */
  122.  
  123. const    short                kInsetPixelsConst = 30 ;    /* num of pixels to inset view by  */
  124. /* error codes  */
  125. enum {
  126.     kNoMenuBar = 1,
  127.     kNoQD3DViewerLib,
  128.     kNoAEVTSupport
  129. } ;
  130.  
  131. /* menu resource IDs  */
  132. enum {
  133.     mInteractiveRendererMenu = 1,    /* hierarchical, stored in the view menu  */
  134.     mNonInteractiveRendererMenu ,    /* hierarchical, stored in final dialog  */
  135.     mAppleMenu = 128,
  136.     mFileMenu,
  137.     mEditMenu,
  138.     mViewMenu
  139. } ;
  140.  
  141. /* item numbers - Apple menu  */
  142. enum {
  143.     iAppleAboutItem = 1
  144. } ;
  145.  
  146. /* item numbers - File menu  */
  147. enum {
  148.     iFileNewItem = 1,
  149.     iFileOpenItem,
  150.     iFileCloseItem = 4,
  151.     iFileSaveItem,
  152.     iFileSaveAsItem,
  153.     iFileRevertItem,
  154.     iFilePageSetupItem = 9,
  155.     iFilePrintItem,
  156.     iFileQuitItem = 12
  157. } ;
  158.  
  159. /* item numbers - Edit menu  */
  160. enum {
  161.     iEditUndoItem = 1,
  162.     iEditCutItem = 3,
  163.     iEditCopyItem,
  164.     iEditPasteItem,
  165.     iEditClearItem = 7,
  166.     iEditRendererPrefsItem = 9
  167. } ;
  168.  
  169. /* item numbers - View menu  */
  170. enum {
  171.     iViewRendererItem = 1,
  172.     iViewFinalRendererItem,
  173.     iViewBadgeItem = 4,
  174.     iViewCameraButtonItem = 6,
  175.     iViewTruckButtonItem,
  176.     iViewOrbitButtonItem,
  177.     iViewZoomButtonItem,
  178.     iViewDollyButtonItem,
  179.     iViewInsetNFrameItem = 12,
  180.     iViewSetBackgroundColorItem
  181. } ;
  182.  
  183. /* items in the final quality render menu */
  184. enum {
  185.     kFinalRendrOK = 1,
  186.     kFinalRendrCancel,
  187.     kFinalRendrIcon,
  188.     kFinalRendrTitle,
  189.     kFinalRendrText,
  190.     kFinalRendrSep1,
  191.     kFinalRendrSep2,
  192.     kFinalRendrSep3,
  193.     kFinalRendrPopup,
  194.     kFinalRendrConfigure,
  195.     kFinalRendrWinSzTxt,
  196.     kFinalRendrHtTxt,
  197.     kFinalRendrWiTxt,
  198.     kFinalRendrHeight,
  199.     kFinalRendrWidth
  200. } ;
  201.  
  202.  
  203. /* res ID's for small picts used in the progress bar dialog */
  204. enum {
  205.     kResIDStartCap = 1028,
  206.     kResIDEndCap,
  207.     kResIDDropShadow
  208. } ;
  209.  
  210.  
  211. /*------------------------------------------------------------ */
  212.  
  213. /*
  214.  * type definitions - these magic numbers are the first field of the struct
  215.  * that we stuff in the window's refcon field
  216.  */
  217.  
  218. /*
  219.  * as this app grow's I'm in the process of factoring it, here's a list
  220.  * of functions that can be stuffed in the document record 
  221.  */
  222. typedef    void         (*AdjustMenusProc)( WindowPtr  theWindow )    ;
  223. typedef Boolean     (*HandleEventProc)( WindowPtr theWindow, EventRecord *theEventRecord) ;
  224. typedef    void         (*UpdateContentProc)( WindowPtr  theWindow ) ;
  225. typedef WindowPtr     (*NewProc)( unsigned char *windowTitle ) ;
  226. typedef OSErr         (*SaveAsProc)( WindowPtr theWindow ) ;
  227. typedef OSErr         (*SaveProc)( WindowPtr theWindow ) ;
  228. typedef OSErr         (*RevertProc)( WindowPtr theWindow ) ;
  229. typedef WindowPtr     (*OpenProc)( FSSpec *theFSSpec ) ;
  230. typedef OSErr         (*CloseProc)( WindowPtr theWindow ) ;
  231. typedef short        (*CountPagesProc)( WindowPtr theWindow, Rect *pageRect ) ;
  232. typedef void        (*PrintPageProc)( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ;
  233. typedef    void         (*PrePrintProc)( WindowPtr  theWindow )    ;
  234. typedef    void         (*PostPrintProc)( WindowPtr  theWindow )    ;
  235. typedef    OSErr        (*CutProc)( WindowPtr    theWindow ) ;
  236. typedef    OSErr        (*CopyProc)( WindowPtr    theWindow ) ;
  237. typedef    OSErr        (*PasteProc)( WindowPtr    theWindow ) ;
  238. typedef    OSErr        (*ClearProc)( WindowPtr    theWindow ) ;
  239. typedef    OSErr        (*UndoProc)( WindowPtr    theWindow ) ;
  240.  
  241. /*
  242.  * This struct is used to store related items for a progress bar,
  243.  * these cached items can then be used when updating the PB
  244.  */
  245. typedef struct {
  246.     DialogPtr        thePBDialog ;        /* the dialog containing a 14 pixel high user item  *
  247.                                          * within which the PB is drawn                     */
  248.     short            thePBItemNumber ;    /* item number in the DITL for the PB user item */
  249.     Rect            thePBRect ;            /* it's rect, local coodinates in the dialog */
  250.     
  251.     GWorldPtr        thePBGWorld ;        /* a GWorld that is used to draw the pb, it's then blitted to the dialog */
  252.     
  253.     long            thePBMaxValue ;        /* the maximum value the PB can be */
  254.     long            thePBCurrValue ;    /* the current value for the progress bar */
  255.     
  256. } ProgressBarDlogInfoData, **ProgressBarDlogInfoHdl ;
  257.  
  258.  
  259.  
  260. /*
  261.  * this is a struct that contains the fp's associated with a document class
  262.  * later we'll use this to set up menus.  If a fp is null then the menu is 
  263.  * disabled, this will really reduce the size of the adjust menus proc.
  264.  *
  265.  * Each document record will have this as the second field.
  266.  */
  267.  
  268. typedef struct Procs {
  269.     AdjustMenusProc        adjustMenusP ;        /* fix up window specific menus */
  270.     UpdateContentProc    updateWindowP ;        /* redraw the window */
  271.     HandleEventProc        handleEventP ;        /* handle events for the window */
  272.     NewProc                newP ;                /* do window specific stuff post create (unused at the moment) */
  273.     SaveAsProc            saveAsP ;            /* save the window contens ask for a file */
  274.     SaveProc            saveP ;                /* save the window contents to the original file */
  275.     RevertProc            revertP ;            /* revert to the last saved copy of the windows file */
  276.     OpenProc            openP ;                /* read in some document data */
  277.     CloseProc            closeP ;            /* close and destroy */
  278.     CountPagesProc        countPagesP ;        /* count the number of pages for a print job */
  279.     PrintPageProc        printPageP ;        /* print one page */
  280.     PrePrintProc        prePrintP ;            /* stuff to do before printing */
  281.     PostPrintProc        postPrintP ;        /* stuff to do after printing */
  282.     CutProc                cutProc ;            /* handle clipboard cut, same as copy followed by clear */
  283.     CopyProc            copyProc ;            /* handle clipboard copy */
  284.     PasteProc            pasteProc ;            /* paste compatible scrap type from the scrap */
  285.     ClearProc            clearProc ;            /* clear the document contents without a save to the scrap */
  286.     UndoProc            undoProc ;            /* undo the last action - if supported */
  287. } Procs ;
  288.  
  289.  
  290. /*
  291.  * eventually to make a new doc, we'll just define the structure of the private 
  292.  * field for each class.  Right now they are kind of copies which can be cast around.
  293.  *
  294.  * Make sure that the fields are in the same order, again this is something I'm 
  295.  * planning to fix.
  296.  */
  297. typedef struct {
  298.     unsigned long        fDocumentMagic ;    /* use this to describe the contents of the fPrivate field */
  299.     Procs                *procs ;            /* a pointer to a set of function pointers for this window type */
  300.     THPrint                fPrintRec ;            /* print record so we can print the doc contents */
  301.     void                *fPrivate ;            /* the private data associated with this class */
  302.     
  303. } Document, *DocumentPtr, **DocumentHdl ;
  304.  
  305. /* these structures get stuffed in the private field of a generic document record */
  306. typedef struct {
  307.     TQ3ViewerObject        fViewer ;        /* stores reference to the viewer object  */
  308.     GWorldPtr            fGWorld ;        /* used temporarily during printing */
  309.     FSSpec                fFSSpec    ;        /* reference to the file for the document  */
  310. } ViewerData, *ViewerDataPtr, **ViewerDataHdl ;
  311.  
  312.  
  313. typedef struct {
  314.     GWorldPtr            fGWorld ;        /* a buffer that stores the picture */
  315. } PictData, *PictDataPtr, **PictDataHdl ;
  316.  
  317.  
  318. /*
  319.  * Structure for the private data for a popup control.
  320.  * This structure is documented on page 5-77 
  321.  * Inside Macintosh: Macintosh Toolbox Essentials
  322. */
  323. typedef struct popupPrivateData {
  324.     MenuHandle     mHandle;      /* the popup menu handle */
  325.     short         mID;         /* the popup menu ID */
  326.     /*
  327.      * after these two public fields is the mPrivate private data, 
  328.      * which may be any old size and should not be messed with 
  329.      */
  330. }    popupPrivateData;
  331.  
  332. /*------------------------------------------------------------ */
  333.  
  334. /* function prototypes for the application  */
  335.  
  336. void             SetUpRendererMenu( void ) ;
  337. void             TearDownRendererMenu( void ) ;
  338.  
  339. void            LoadApplicationDialogs( void ) ;
  340. void            LoadMenuBarForApplication( short myMenuBarID ) ;
  341. void             FatalAlert( short theErrorMessage ) ;
  342. void            InitializeToolBox( void ) ;
  343. Boolean         HasQuickDraw3DViewer( void ) ;
  344. Boolean         SupportsAEVT( void ) ;
  345. void             RegisterRequiredAppleEventHandlers( void ) ;
  346.  
  347. /* routines to handle the renderer progress bar */
  348. ProgressBarDlogInfoHdl PB_New( 
  349.                 DialogPtr     thePBDialog,
  350.                 short         thePBItemNumber,
  351.                 long        maxValue,
  352.                 long        currValue ) ;
  353.  
  354. void            PB_Update(ProgressBarDlogInfoHdl theInfo ) ;
  355. void            PB_Delete(ProgressBarDlogInfoHdl theInfo ) ;
  356.  
  357. pascal OSErr     HandleCoreAppleEventOfTypeOAPP(    AppleEvent *theAppleEvent, 
  358.                                 AppleEvent *theAppleEventReply, 
  359.                                 long userDefinedReferenceConstant) ;
  360.                                 
  361. pascal OSErr     HandleCoreAppleEventOfTypeODOC( AppleEvent *theAppleEvent, 
  362.                                 AppleEvent *theAppleEventReply, 
  363.                                 long userDefinedReferenceConstant) ;
  364.                                 
  365. pascal OSErr     HandleCoreAppleEventOfTypePDOC( AppleEvent *theAppleEvent, 
  366.                                 AppleEvent *theAppleEventReply,
  367.                                 long userDefinedReferenceConstant) ;
  368.                                 
  369. pascal OSErr     HandleCoreAppleEventOfTypeQUIT( AppleEvent *theAppleEvent, 
  370.                                 AppleEvent *theAppleEventReply,
  371.                                 long userDefinedReferenceConstant) ; 
  372.                                 
  373. void            MainEventLoop( void ) ; 
  374. TQ3Boolean         HandleEvent( const EventRecord *theEventRecord ) ;
  375.  
  376. void             HandleKeyPress(EventRecord *theEventRecord) ;
  377. void             HandleMenuCommand(long menuResult) ;
  378. void             HandleAppleMenu( short menuItem ) ;
  379. void             HandleFileMenu( short menuItem ) ;
  380. OSErr             HandleFilePageSetupItem( WindowPtr theWindow ) ;
  381. OSErr             HandleFilePrintItem( WindowPtr theWindow ) ;
  382. OSErr             HandleFileQuitItem( void ) ;
  383. void             HandleEditMenu( short menuItem ) ;
  384. pascal Boolean     OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit) ;
  385. void             HandleViewFinalRendererOption( void ) ;
  386. void             HandleInteractiveRendererMenu( short menuItem ) ;
  387. void             HandleViewMenu( short menuItem ) ;
  388. OSErr             GetViewerVersion( unsigned long *major, unsigned long *minor ) ;
  389.  
  390. Boolean         BackgroundColor(RGBColor *theRGBColor, unsigned char *thePrompt ) ;
  391. void             AdjustMenus( void ) ;
  392. void            DoDrawGrowIcon(WindowPtr theWindow) ;
  393.  
  394. WindowPtr         DoCreateNewViewerWindow( unsigned char *windowName ) ;
  395.  
  396. void            ViewerWindow_Update( WindowPtr  theWindow ) ;
  397. void             ViewerWindow_AdjustMenus( WindowPtr  theWindow ) ;
  398. Boolean            ViewerWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord) ;
  399. WindowPtr         ViewerWindow_New( unsigned char *windowTitle ) ;
  400. OSErr             ViewerWindow_SaveAs( WindowPtr theWindow ) ;
  401. OSErr             ViewerWindow_Save( WindowPtr theWindow ) ;
  402. OSErr             ViewerWindow_Revert( WindowPtr theWindow ) ;
  403. WindowPtr         ViewerWindow_Open( FSSpec *theFSSpec ) ;
  404. OSErr             ViewerWindow_Close( WindowPtr theWindow ) ;
  405. short            ViewerWindow_CountPages( WindowPtr theWindow, Rect *pageRect ) ;
  406. void            ViewerWindow_PrintPage( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ;
  407. void             ViewerWindow_PrePrint( WindowPtr theWindow ) ;
  408. void             ViewerWindow_PostPrint( WindowPtr theWindow ) ;
  409. OSErr            ViewerWindow_Cut( WindowPtr    theWindow ) ;
  410. OSErr            ViewerWindow_Copy( WindowPtr    theWindow ) ;
  411. OSErr            ViewerWindow_Paste( WindowPtr    theWindow ) ;
  412. OSErr            ViewerWindow_Clear( WindowPtr    theWindow ) ;
  413. OSErr            ViewerWindow_Undo( WindowPtr    theWindow ) ;
  414.  
  415. WindowPtr         DoCreateNewPictWindow( unsigned char *windowName, long windWidth, long windHeight ) ;
  416. void            PictWindow_Update( WindowPtr  theWindow ) ;
  417. void             PictWindow_AdjustMenus( WindowPtr  theWindow ) ;
  418. Boolean            PictWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord) ;
  419. WindowPtr         PictWindow_New( unsigned char *windowTitle ) ;
  420. OSErr             PictWindow_SaveAs( WindowPtr theWindow ) ;
  421. OSErr             PictWindow_Save( WindowPtr theWindow ) ;
  422. OSErr             PictWindow_Revert( WindowPtr theWindow ) ;
  423. WindowPtr         PictWindow_Open( FSSpec *theFSSpec ) ;
  424. OSErr             PictWindow_Close( WindowPtr theWindow ) ;
  425. short            PictWindow_CountPages( WindowPtr theWindow, Rect *pageRect ) ;
  426. void            PictWindow_PrintPage( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ;
  427. void             PictWindow_PrePrint( WindowPtr theWindow ) ;
  428. void             PictWindow_PostPrint( WindowPtr theWindow ) ;
  429. OSErr             PictWindow_Copy( WindowPtr theWindow ) ;
  430.  
  431. /*------------------------------------------------------------ */
  432.  
  433. /* global variables  */
  434. DialogPtr            gFinalRenderDialog = NULL ;    /* the non interactive renderer dial0g */
  435. DialogPtr            gProgressModelessDialog = NULL ;
  436.  
  437. Boolean                gQuitFlag = false ;    /* set to true to quit application  */
  438. AEAddressDesc        gSelfAddress;        /* A self-addressed address descriptor record  */
  439.  
  440. /* these are used for the menus */
  441. static TQ3ObjectType        pInteractiveTypes[ kMaxRendererCount ] ; /* renderer types installed - includes plug-ins */
  442. static TQ3ObjectType        pNonInteractiveTypes[ kMaxRendererCount ] ; /* renderer types installed - includes plug-ins */
  443. static long                    pNonInteractiveRendererCount = 0;    /* the number of non-interactive renderers installed on this system */
  444. static long                    pInteractiveRendererCount = 0;        /* the number of interactive renderers installed on this system */
  445. static Boolean                pHasFinalQualityRenderer = false ;    /* set true if one or more non interactive renderers are installed */
  446.  
  447. /* 
  448.  * this is a list of the installed renderers that we can use to switch easily. 
  449.  * By this point you are probably muttering that this app has way to many globals,
  450.  * and you might be right, however keeping a list of renderer objects makes sense.
  451.  * The most obvious reason to build a list of the available renderers, together
  452.  * with an instance of each mish be efficiency considerations, but the real reason
  453.  * is somewhat more subtle.  We want renderer prefs to be "sticky".  In other words
  454.  * if I set prefs for a renderer I want those prefs to be the same for multiple
  455.  * uses of the renderer.  Just setting the renderer is not enough, since each time 
  456.  * a renderer object is created it is created with the default set of prefs which
  457.  * may not be what I selected last time I bought the prefs dialog up.
  458.  *
  459.  * The way this structure is used is to build a list of renderer types and an 
  460.  * instance of each when the application is launched, then this list is used
  461.  * whenever renderer prefs need to be set or when a new renderer is selected.
  462.  * This way the prefs will stay with the renderer for the life time of the program.
  463.  *
  464.  * This list contains both interactive and non interactive renderers, it has no
  465.  * real order (first come first served) and is seached linearly by renderer type.
  466.  *
  467.  * In the future, it might be good to build a list of renderer prefs for each 
  468.  * document and save these along with the document, or to have a global list of
  469.  * prefs for the application..
  470.  */
  471.  
  472. static struct {
  473.     TQ3ObjectType         fRendererType ;        /* the object type for this renderer */
  474.     TQ3RendererObject    fRendererObject ;    /* an instance of the renderer type */    
  475. } pRendererList[ 2 * kMaxRendererCount ] ;
  476.  
  477. static short         pRendererCount = 0 ;        /* indexes the pRendererList array */
  478.  
  479. ModalFilterUPP        gModalFilterProcUPP ; 
  480.  
  481. /********************************************************************************
  482.  * Colors used to draw the progress bar 
  483.  */
  484.  
  485. /* 
  486.  
  487. I got these by dumping a scroll bar from the MacOS 8 finder and poking around in photoshop.
  488.  
  489. Color table, byte value (e.g. from photoshop) on LHS
  490.  
  491. 8bit    16bit        16bit (Hex)
  492.  
  493. 0,         0,             0x0000
  494. 51,     13107,         0x3333
  495. 102,     26214,         0x6666
  496. 136,     34952,         0x8888
  497. 153,     39321,        0x9999
  498. 170,     43690,        0xaaaa
  499. 187,     48059,        0xbbbb
  500. 204,     52428,        0xcccc
  501. 221,     56797,        0xdddd
  502. 255,     65535,        0xffff
  503.  
  504. */
  505.  
  506. const RGBColor        RGBBlack    = { 0x0000, 0x0000, 0x0000 } ;
  507. const RGBColor        RGBDkGrey    = { 0x8888, 0x8888, 0x8888 } ;
  508. const RGBColor        RGBMedGrey    = { 0xaaaa, 0xaaaa, 0xaaaa } ;
  509. const RGBColor        RGBGrey        = { 0xbbbb, 0xbbbb, 0xbbbb } ;
  510. const RGBColor        RGBLtGrey    = { 0xdddd, 0xdddd, 0xdddd } ;
  511. const RGBColor        RGBWhite    = { 0xffff, 0xffff, 0xffff } ;
  512.  
  513. /* blue shades used */
  514. const RGBColor        RGBDkBlue    = { 0x3333, 0x3333, 0x6666 } ;
  515. const RGBColor        RGBMedBlue    = { 0x6666, 0x6666, 0x9999 } ;
  516. const RGBColor        RGBBlue        = { 0x9999, 0x9999, 0xcccc } ;
  517. const RGBColor        RGBLtBlue    = { 0xcccc, 0xcccc, 0xffff } ;
  518.  
  519.  
  520. static    GWorldPtr    theStartCap     = NULL;
  521. static    GWorldPtr    theEndCap         = NULL ;
  522. static    GWorldPtr    theDropShadow     = NULL ;
  523.  
  524. const unsigned long kViewerMagic    =    0xBADB00CA ;    /* viewer windows */
  525. const unsigned long kPICTMagic        =    0xBADABADA ;    /* picture windows */
  526.  
  527. /* these MUST be in the same order as above or bad things happen.
  528.  * function procs for the regular viewer window.  Setting these up
  529.  * this way is a little dangerous, if the fields get jumbled up
  530.  * unexpected results can happen, it might make more sense to use
  531.  * a metahandler approach to install the methods - like QD3D
  532.  * extensions...
  533.  */
  534. Procs viewerProcs = { 
  535.     ViewerWindow_AdjustMenus, 
  536.     ViewerWindow_Update, 
  537.     ViewerWindow_HandleEvent,
  538.     ViewerWindow_New, 
  539.     ViewerWindow_SaveAs, 
  540.     ViewerWindow_Save, 
  541.     ViewerWindow_Revert, 
  542.     ViewerWindow_Open, 
  543.     ViewerWindow_Close,
  544.     ViewerWindow_CountPages,
  545.     ViewerWindow_PrintPage,
  546.     ViewerWindow_PrePrint,
  547.     ViewerWindow_PostPrint,
  548.     ViewerWindow_Cut,
  549.     ViewerWindow_Copy,
  550.     ViewerWindow_Paste,
  551.     ViewerWindow_Clear,
  552.     ViewerWindow_Undo
  553.     
  554. };
  555.  
  556. /* function procs for the pict window */
  557. Procs pictProcs = { 
  558.     PictWindow_AdjustMenus, 
  559.     PictWindow_Update, 
  560.     PictWindow_HandleEvent,
  561.     PictWindow_New, 
  562.     PictWindow_SaveAs, 
  563.     PictWindow_Save, 
  564.     PictWindow_Revert, 
  565.     PictWindow_Open, 
  566.     PictWindow_Close,
  567.     PictWindow_CountPages,
  568.     PictWindow_PrintPage,
  569.     NULL,                        /* pre print method is not supported */
  570.     NULL,                        /* post print method is not supported */
  571.     NULL,                        /* cut method is not supported */
  572.     PictWindow_Copy,
  573.     NULL,                        /* paste method is not supported */
  574.     NULL,                        /* clear method is not supported */
  575.     NULL                        /* undo method is not supported */
  576. };
  577.  
  578. /*------------------------------------------------------------ */
  579.  
  580.  
  581. /* REMOVE THIS */
  582.  
  583. #include <Types.h>
  584. #include <Memory.h>
  585. #include <Quickdraw.h>
  586. #include <Gestalt.h>
  587. #include <Fonts.h>
  588. #include <Events.h>
  589. #include <Menus.h>
  590. #include <Windows.h>
  591. #include <TextEdit.h>
  592. #include <Dialogs.h>
  593. #include <OSUtils.h>
  594. #include <ToolUtils.h>
  595. #include <SegLoad.h>
  596. #include <Notification.h>
  597. #include <OSUtils.h>
  598.  
  599.     
  600. /* Prototypes */
  601. Boolean IsVMCurrentlyOn(void) ;
  602.  
  603. static Str255        VMIsCurrentlyOnStr        = "\pVirtual memory is currently on" ;
  604. static Str255        VMIsCurrentlyOffStr        = "\pVirtual memory is currently off" ;
  605.  
  606. static    NMRec        myNotification ;
  607. void notify(void)
  608. {
  609.     OSErr theErr ;
  610.  
  611.     myNotification.qType = nmType ;
  612.     myNotification.nmIcon = NULL ;
  613.     myNotification.nmSound = NULL ;
  614.     myNotification.nmResp = NULL ;
  615.     myNotification.nmRefCon = 0L ;
  616.     
  617.     /* check Gestalt to see if VM is on */
  618.     if( IsVMCurrentlyOn() )
  619.     {
  620.         myNotification.nmStr = VMIsCurrentlyOnStr ;
  621.     
  622.     }
  623.     else
  624.     {
  625.         myNotification.nmStr = VMIsCurrentlyOffStr ;
  626.     
  627.     }
  628.     
  629.     theErr = NMInstall( &myNotification ) ;
  630.     
  631. }
  632.  
  633. /*
  634.  * returns true if the VM is on
  635.  */
  636. Boolean IsVMCurrentlyOn(void)
  637. {
  638.     OSErr theError;
  639.     long response;
  640.         
  641.     theError = Gestalt(gestaltVMAttr, &response);
  642.     if (theError!=noErr)
  643.         return false;
  644.         
  645.     return (response && (response << gestaltVMPresent));
  646. }
  647.  
  648.  
  649. /* END REMOVE THIS */
  650.  
  651. void main(void)
  652. {
  653.     InitializeToolBox() ;
  654.     gModalFilterProcUPP = NewModalFilterProc( OurFilter ) ;
  655.     LoadApplicationDialogs() ;
  656.     LoadMenuBarForApplication( kAppMenuBarID ) ;
  657.  
  658.     /*
  659.      * check that we have AppleEvents, and if so install the
  660.      * AppleEvent handlers for the required AppleEvents
  661.      */
  662.     
  663.     if( SupportsAEVT() ) 
  664.     {
  665.         RegisterRequiredAppleEventHandlers() ;
  666.         
  667.         /*
  668.          * Check that the viewer is installed
  669.          */
  670.         if( HasQuickDraw3DViewer() )
  671.         {
  672.             Q3Initialize() ;
  673.             SetUpRendererMenu() ;
  674.  
  675.             MainEventLoop() ;
  676.             
  677.             TearDownRendererMenu() ;
  678.             Q3Exit() ;
  679.         }
  680.     }
  681.  
  682.     ExitToShell();    
  683.     
  684. }
  685.  
  686. /*------------------------------------------------------------ */
  687.  
  688. /*
  689.  * Load the final quality renderer dialog.  We do this here so
  690.  * that we can set up the menu properly.  Don't display it just 
  691.  * yet though.
  692.  */
  693. void    LoadApplicationDialogs(void)
  694. {
  695.     /* 
  696.      * load the dialog but don't show it.  As a side note since the 
  697.      * dialog is going to be around for a while, the items in the dialog 
  698.      * should not be purgable.
  699.      */
  700.     gFinalRenderDialog = GetNewDialog( kFinalRenderDialogID, NULL, (WindowPtr)-1) ;
  701.     gProgressModelessDialog = GetNewDialog( kProgressBarDlogID, NULL, (WindowPtr)-1) ;
  702.     
  703.     /* the popup menu for the renderers is item 9 */
  704. }
  705.  
  706. /*------------------------------------------------------------ */
  707.  
  708. /*
  709.  * Load the menu bar specified.
  710.  */
  711.  
  712. void LoadMenuBarForApplication( short myMenuBarID )
  713. {
  714.     Handle        menuBar = NULL;
  715.  
  716.     /* 
  717.      *Read menus into menu bar specified by the resource 
  718.      * id passed into this routine by myMenuBarID 
  719.      */
  720.     menuBar = GetNewMBar(myMenuBarID);    
  721.     
  722.     if ( menuBar == NULL )
  723.          ExitToShell();
  724.          
  725.     /* Install the menus we just read in  */              
  726.     SetMenuBar(menuBar);
  727.     
  728.     /* it is now safe to dispose the menu handle  */
  729.     DisposeHandle(menuBar);
  730.     
  731.     /* 
  732.      * this next routine adds the names of desk accessories 
  733.      * to the specified menu, in this case the apple menu
  734.      */
  735.     AppendResMenu( GetMenuHandle( mAppleMenu ), 'DRVR' );
  736.     
  737.     /*
  738.      * now add the two hierarchical menus
  739.      */
  740.     InsertMenu(GetMenu( mInteractiveRendererMenu ), -1);
  741.     
  742.     /* call our routine to grey out menus as appropriate  */
  743.     AdjustMenus() ;
  744.     
  745.     /* finally ensure the new menubar gets drawn  */
  746.     DrawMenuBar();
  747. }
  748. /*------------------------------------------------------------ */
  749.  
  750. /*
  751.  * dispose of the global rtenderer list
  752.  */
  753. void TearDownRendererMenu( void )
  754. {
  755.     long        theIndex ;
  756.     
  757.     for( theIndex = 0; theIndex < pRendererCount ; theIndex++ ) 
  758.         Q3Object_Dispose( pRendererList[ theIndex ].fRendererObject ) ;
  759. }
  760.  
  761.  
  762. /*------------------------------------------------------------ */
  763.  
  764. /*
  765.  * set up the interactive renderer menu and the non interactive 
  766.  * renderer popup menu for the "final render" dialog.  Build up
  767.  * a list of renderer objects in the pRendererList struct to make 
  768.  * switching between renderers easier
  769.  */
  770.  
  771. void SetUpRendererMenu( void ) 
  772. {
  773.     MenuHandle                    theMenu, interactiveRendererMenu, nonInteractiveRendererMenu ;
  774.     TQ3SubClassData                subClassData;
  775.     TQ3ObjectType                *classPointer;
  776.     short                        i;
  777.     TQ3ObjectClassNameString    objectClassName;
  778.     TQ3RendererObject            tempRendererObject ;
  779.     unsigned char                nameBuffer[256] ;
  780.     unsigned long                actualLength ;
  781.     TQ3ObjectClassNameString     objectClassString ;
  782.     Boolean                        isInteractive ;
  783.     popupPrivateData            **myPopupPrivateDataPtr ;
  784.     
  785.     /* some variables for accessing the fields of the dialog */
  786.     short                iKind;
  787.     Handle                iHandle;
  788.     Rect                iRect;
  789.         
  790.     interactiveRendererMenu = GetMHandle(mInteractiveRendererMenu);
  791.  
  792.     /*
  793.      * Set up the dialog renderer popup.  We know the item number for the popup
  794.      * we need to get the menuhandle associated with the control, it is in the private
  795.      * control data field, as documented in Inside Macintosh: Toolbox page 5-77
  796.      */
  797.     
  798.     /* get the control handle for the popup    from the dialog */    
  799.     GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  800.     
  801.     /* extract from the control the menuhandle */
  802.     myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  803.     nonInteractiveRendererMenu = (**myPopupPrivateDataPtr).mHandle ;
  804.     HLock((Handle)nonInteractiveRendererMenu) ;
  805.     
  806.     /* the popup control has a problem under 7.5 and 7.6, since it expects the 
  807.      * menu to alredy be constructed otherwise the default value for the control 
  808.      * is 0, which means nothing is selected after the menu items have been added, 
  809.      * so i put a dummy item in the menu, we need to delete this before adding 
  810.      * any new items
  811.      */
  812.      
  813.     DeleteMenuItem ( nonInteractiveRendererMenu, 1 ) ;
  814.     Q3ObjectHierarchy_GetSubClassData(kQ3SharedTypeRenderer, &subClassData);
  815.     
  816.     classPointer = subClassData.classTypes;
  817.     
  818.     i = subClassData.numClasses;
  819.     
  820.     while( i-- > 0 && pInteractiveRendererCount <= kMaxRendererCount) {
  821.         
  822.         /* 
  823.          * the "generic" renderer is used internally, it can't draw, 
  824.          * so don't display it in any user interface item
  825.          */
  826.         if( *classPointer != kQ3RendererTypeGeneric )
  827.         {
  828.             /*
  829.              * Q3RendererClass_GetNickNameString is only available on 1.5.1, so 
  830.              * check for the existance of this trap before calling.  If the call 
  831.              * is not installed just set the string to NULL, we'll use the class name
  832.              * instead and everthing will be hunky dory.
  833.              */
  834.             if( Q3RendererClass_GetNickNameString != (void *)kUnresolvedCFragSymbolAddress ) 
  835.                 Q3RendererClass_GetNickNameString(*classPointer, objectClassString );
  836.             else
  837.                 objectClassString[0] = '\0' ;
  838.                 
  839.             /*
  840.              * Create an instance of a renderer object and then call 
  841.              * Q3Renderer_IsInteractive to determine if the renderer is 
  842.              * an interactive renderer (this is something the renderer 
  843.              * tells QuickDraw 3D).  Stash the renderer and the type in
  844.              * the pRendererList structure array.
  845.              */
  846.              
  847.             tempRendererObject = Q3Renderer_NewFromType( *classPointer ) ;
  848.             isInteractive = Q3Renderer_IsInteractive( tempRendererObject ) ;
  849.             
  850.             /* cache the renderer and type */
  851.             pRendererList[ pRendererCount ].fRendererType = *classPointer ;
  852.             pRendererList[ pRendererCount ].fRendererObject = tempRendererObject;
  853.             pRendererCount++ ;        /* bump the count of elements in the array */
  854.             
  855.             if( isInteractive )
  856.             {
  857.                 theMenu = interactiveRendererMenu ;
  858.                 pInteractiveTypes[pInteractiveRendererCount++] = *classPointer ;
  859.             }
  860.             else
  861.             {
  862.                 theMenu = nonInteractiveRendererMenu ;
  863.                 pHasFinalQualityRenderer = true ;
  864.                 pNonInteractiveTypes[pNonInteractiveRendererCount++] = *classPointer ;
  865.             }
  866.             /*
  867.              * check to see if we got a string back, if not use the renderer class name
  868.              */
  869.                 
  870.             if( objectClassString[0] == '\0' )
  871.             {
  872.                 /* the renderer did not provide the name, just use the class name */
  873.                 Q3ObjectHierarchy_GetStringFromType(*classPointer, objectClassName);
  874.                 
  875.                 AppendMenu(theMenu,c2pstr((char *)objectClassName));
  876.             }
  877.             else
  878.             {
  879.                 AppendMenu(theMenu,c2pstr(objectClassString));
  880.             }
  881.                 
  882.         }
  883.         
  884.         classPointer++ ;        
  885.     }
  886.     
  887.     HLock((Handle)nonInteractiveRendererMenu) ;
  888.     
  889.     /* null terminate the arrays */
  890.     pInteractiveTypes[pInteractiveRendererCount] = NULL ;
  891.     pNonInteractiveTypes[pInteractiveRendererCount] = NULL ;
  892.     pRendererList[ pRendererCount ].fRendererType = 0L ;
  893.     pRendererList[ pRendererCount ].fRendererObject = NULL;
  894.     
  895.     Q3ObjectHierarchy_EmptySubClassData( &subClassData ) ;
  896. }
  897.  
  898. /*------------------------------------------------------------ */
  899.  
  900. /*
  901.  * Display an alert and quit.
  902.  */
  903.  
  904. void FatalAlert( short theErrorMessage )
  905. {
  906.     unsigned char    *thePString, theErrorStr[256] ;
  907.     
  908.     thePString = theErrorStr ;
  909.     
  910.     GetIndString( thePString, kErrorAlertStrings, theErrorMessage ) ;
  911.     ParamText( thePString, "\p", "\p", "\p" ) ;
  912.     StopAlert( kFatalAlert, NULL ) ;
  913.     ExitToShell() ;
  914. }
  915.  
  916. /*------------------------------------------------------------ */
  917.  
  918. /*
  919.  * Initialize all the needed managers.
  920.  */
  921.  
  922. void     InitializeToolBox( void )
  923. {
  924.     /*
  925.      * Initialize the toolbox managers
  926.      */
  927.     InitGraf((Ptr)&qd.thePort);
  928.     InitFonts();
  929.     InitWindows();
  930.     InitMenus();
  931.     TEInit();
  932.     InitDialogs((long)NULL);
  933.     InitCursor();
  934.  
  935.     /*
  936.      * must call this so that the heap is expanded to maximum
  937.      * size before calling any viewer routines
  938.      */
  939.     MaxApplZone() ;
  940.     
  941. }
  942.  
  943. /*------------------------------------------------------------ */
  944.  
  945. /*
  946.  * return true if the viewer is installed
  947.  */
  948.  
  949. Boolean     HasQuickDraw3DViewer( void )
  950. {
  951.     return((long) Q3ViewerNew != kUnresolvedCFragSymbolAddress) ;
  952. }
  953.  
  954. /*------------------------------------------------------------ */
  955.  
  956. /*
  957.  * returns true if the platform supports appleevents - we won't run
  958.  * if it doesn't
  959.  */
  960. Boolean SupportsAEVT(void)
  961. {
  962.     OSErr theError;
  963.     long response;
  964.         
  965.     theError = Gestalt(gestaltAppleEventsAttr,&response);
  966.     if (theError!=noErr)
  967.         return false;
  968.         
  969.     return (response && (response << gestaltAppleEventsPresent));
  970. }
  971.  
  972.  
  973. /********************************************************************************
  974.  * LoadPictIntoGWorld - read pict from the current resource chain, create a 32 bit
  975.  * GWorld the size of the pict, image the pict into the GWorld, dispose of the 
  976.  * pict.  Return a reference to the gworld.
  977.  */
  978.  
  979. static GWorldPtr LoadPictIntoGWorld( short resID )
  980. {
  981.     Rect        pictRect ;
  982.     GWorldPtr    theGWorld = NULL;
  983.     QDErr        theErr ;
  984.     PicHandle    aPicH = GetPicture(resID);
  985.     
  986.     if( aPicH != NULL ) 
  987.     {
  988.         /* create a GWorld the size of the pict */
  989.         pictRect.top = (**aPicH).picFrame.top ;
  990.         pictRect.left = (**aPicH).picFrame.left ;
  991.         pictRect.bottom = (**aPicH).picFrame.bottom ;
  992.         pictRect.right = (**aPicH).picFrame.right ;
  993.         OffsetRect(&pictRect, -pictRect.left, -pictRect.top);
  994.         
  995.         theErr = NewGWorld(&theGWorld, 32, &pictRect, NULL, NULL, 0L) ;
  996.         if( theErr != noErr )
  997.             theGWorld = NULL ;
  998.         else
  999.         {
  1000.             CGrafPtr        savedPort ;
  1001.             GDHandle        gdh ;
  1002.             
  1003.             GetGWorld( &savedPort, &gdh);
  1004.             SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  1005.             
  1006.             DrawPicture( aPicH, &theGWorld->portRect ) ;
  1007.             
  1008.             SetGWorld( savedPort, gdh);
  1009.         }
  1010.     }
  1011.     
  1012.     return theGWorld ;
  1013. }
  1014.  
  1015.  
  1016. /*------------------------------------------------------------ */
  1017.  
  1018. /*
  1019.  * PBNew set up for a new progress bar in a dialog, get all of the info we'll
  1020.  * need in order to draw it and allocate a GWorld to composite the Scroll bar.
  1021.  */
  1022.  
  1023. ProgressBarDlogInfoHdl    PB_New( 
  1024.     DialogPtr     thePBDialog, 
  1025.     short         thePBItemNumber,
  1026.     long        maxValue,
  1027.     long        currValue )
  1028. {
  1029.     ProgressBarDlogInfoHdl    theInfo ;
  1030.     
  1031.     /* first make sure we have the requisite pict's loaded */
  1032.     if(theStartCap == NULL )
  1033.         theStartCap = LoadPictIntoGWorld( kResIDStartCap ) ;
  1034.         
  1035.     if(theEndCap == NULL )
  1036.         theEndCap = LoadPictIntoGWorld( kResIDEndCap ) ;
  1037.         
  1038.     if(theDropShadow == NULL )
  1039.         theDropShadow = LoadPictIntoGWorld( kResIDDropShadow ) ;
  1040.             
  1041.     theInfo = (ProgressBarDlogInfoHdl)NewHandle(sizeof(ProgressBarDlogInfoData)) ;
  1042.     if( theInfo != NULL ) 
  1043.     {
  1044.         short        itemType ;
  1045.         Handle        item ;
  1046.         Rect        box ;
  1047.         QDErr        theErr ;
  1048.         GWorldPtr    theOffscreen ;
  1049.         
  1050.         /* stash the other values passed in */
  1051.         (**theInfo).thePBDialog = thePBDialog ;            /* reference to the dialog containing the progressbar */
  1052.         (**theInfo).thePBItemNumber = thePBItemNumber ;    /* the item number in the dialog that is the progress bar */
  1053.         (**theInfo).thePBMaxValue = maxValue ;            /* the max value that the progress bar can be */
  1054.         (**theInfo).thePBCurrValue = currValue ;        /* current value of the progress bar (usually 0 ) */
  1055.         
  1056.         /* get the rect of the given item number in local co-ordinates */
  1057.         GetDialogItem(thePBDialog, thePBItemNumber, &itemType, &item, &box) ;
  1058.                 
  1059.         /* save the box information, we'll use this to draw into */
  1060.         (**theInfo).thePBRect.top         = box.top ;
  1061.         (**theInfo).thePBRect.left         = box.left ;
  1062.         (**theInfo).thePBRect.bottom     = box.bottom ;
  1063.         (**theInfo).thePBRect.right     = box.right ;
  1064.         
  1065.         OffsetRect( &box, -box.left, -box.top ) ;
  1066.     
  1067.         /* make a new GWorld for the progress bar, we composite the PB in here and copy to the screen */
  1068.         theErr = NewGWorld( &theOffscreen, 32, &box, NULL, NULL, 0L);
  1069.         if( theErr != noErr || theOffscreen == NULL )
  1070.         {
  1071.             /* we couldn't create the offscree, zero the info rec. */
  1072.             DisposeHandle((Handle)theInfo) ;
  1073.             theInfo = NULL ;
  1074.         }
  1075.         else
  1076.         {
  1077.             (**theInfo).thePBGWorld = theOffscreen ;
  1078.         }
  1079.     }
  1080.     return theInfo ;
  1081. }
  1082.  
  1083. /*------------------------------------------------------------ */
  1084.  
  1085. /*
  1086.  * Redraw the progress bar, assumes the caller has just updated the 
  1087.  * value in current.
  1088.  */
  1089. void    PB_Update( ProgressBarDlogInfoHdl theInfo )
  1090. {
  1091.     CGrafPtr    savedPort ;
  1092.     GDHandle    gdh ;
  1093.     Rect        theFrame ;
  1094.     short        numPixels ;
  1095.     Rect        tmpRect ;
  1096.     
  1097.     Rect        destRect ;
  1098.     
  1099.     HLock((Handle)theInfo) ;
  1100.     
  1101.     GetGWorld( &savedPort, &gdh);
  1102.     SetGWorld( (CGrafPtr)(**theInfo).thePBGWorld, NULL ) ;
  1103.         
  1104.     /* fill the entire rect with the default grey */
  1105.     
  1106.     RGBForeColor(&RGBGrey) ;
  1107.     PaintRect(&(**theInfo).thePBGWorld->portRect) ;
  1108.     
  1109.     /* frame the outline of the progress bar */
  1110.     
  1111.     /* copy the rect to the frame rect */
  1112.     theFrame.top     = (**theInfo).thePBGWorld->portRect.top ;
  1113.     theFrame.left     = (**theInfo).thePBGWorld->portRect.left ;
  1114.     theFrame.bottom    = (**theInfo).thePBGWorld->portRect.bottom ;
  1115.     theFrame.right     = (**theInfo).thePBGWorld->portRect.right ;
  1116.     
  1117.     /* how long is the progress part of the progress bar in pixels */
  1118.     numPixels = ((float)(**theInfo).thePBCurrValue / (**theInfo).thePBMaxValue ) 
  1119.                     * ((**theInfo).thePBGWorld->portRect.right - (**theInfo).thePBGWorld->portRect.left - 2) ;
  1120.     
  1121.     /* and inset for the frame */
  1122.     InsetRect( &theFrame, 1, 1 ) ;
  1123.  
  1124.     RGBForeColor( &RGBBlack ) ;
  1125.     FrameRect( &theFrame ) ;
  1126.     
  1127.     /* apply highlight to top and left edges (outermost) */
  1128.     MoveTo( (**theInfo).thePBGWorld->portRect.left, 
  1129.             (**theInfo).thePBGWorld->portRect.bottom - 1) ;
  1130.  
  1131.     RGBForeColor( &RGBLtGrey ) ;
  1132.     MoveTo( (**theInfo).thePBGWorld->portRect.left, 
  1133.             (**theInfo).thePBGWorld->portRect.bottom - 2 ) ;
  1134.  
  1135.     
  1136.     RGBForeColor( &RGBMedGrey ) ;
  1137.     LineTo( (**theInfo).thePBGWorld->portRect.left, 
  1138.             (**theInfo).thePBGWorld->portRect.top );        
  1139.             
  1140.     LineTo( (**theInfo).thePBGWorld->portRect.right - 1, 
  1141.             (**theInfo).thePBGWorld->portRect.top );
  1142.             
  1143.     /* hit the pixel at the top left */        
  1144.     RGBForeColor( &RGBLtGrey ) ;
  1145.     LineTo( (**theInfo).thePBGWorld->portRect.right, 
  1146.             (**theInfo).thePBGWorld->portRect.top );
  1147.     
  1148.     /* right and bottom edges */
  1149.     RGBForeColor( &RGBWhite ) ;
  1150.     MoveTo( (**theInfo).thePBGWorld->portRect.right - 1, 
  1151.             (**theInfo).thePBGWorld->portRect.top + 1 ) ;
  1152.             
  1153.     LineTo( (**theInfo).thePBGWorld->portRect.right - 1, 
  1154.             (**theInfo).thePBGWorld->portRect.bottom - 1);
  1155.     
  1156.     LineTo( (**theInfo).thePBGWorld->portRect.left + 1, 
  1157.             (**theInfo).thePBGWorld->portRect.bottom - 1);
  1158.     
  1159.     
  1160.     /* apply highlight to top and left edges (innermost) */
  1161.     MoveTo( (**theInfo).thePBGWorld->portRect.left + 2, 
  1162.             (**theInfo).thePBGWorld->portRect.bottom - 3) ;
  1163.     
  1164.     RGBForeColor( &RGBDkGrey ) ;
  1165.     
  1166.     LineTo( (**theInfo).thePBGWorld->portRect.left + 2, 
  1167.             (**theInfo).thePBGWorld->portRect.top + 2 ) ;        
  1168.             
  1169.     LineTo( (**theInfo).thePBGWorld->portRect.right - 4, 
  1170.             (**theInfo).thePBGWorld->portRect.top + 2) ;
  1171.     
  1172.     /* hit the single pixel in the inside corner */
  1173.     RGBForeColor( &RGBGrey ) ;
  1174.     
  1175.     LineTo( (**theInfo).thePBGWorld->portRect.right - 3, 
  1176.             (**theInfo).thePBGWorld->portRect.top + 2) ;
  1177.     
  1178.  
  1179.     /* right and bottom */
  1180.     RGBForeColor( &RGBLtGrey ) ;
  1181.     
  1182.     LineTo( (**theInfo).thePBGWorld->portRect.right - 3, 
  1183.             (**theInfo).thePBGWorld->portRect.bottom - 3) ;
  1184.             
  1185.     LineTo( (**theInfo).thePBGWorld->portRect.left + 3, 
  1186.             (**theInfo).thePBGWorld->portRect.bottom - 3) ;
  1187.             
  1188.     RGBForeColor( &RGBBlack ) ;
  1189.     
  1190.     /* set up the rect for the progress part of the PB */
  1191.     tmpRect.top = theFrame.top ;
  1192.     tmpRect.left = theFrame.left  ;
  1193.     tmpRect.bottom = theFrame.bottom ;
  1194.     tmpRect.right = theFrame.right ;
  1195.     
  1196.     InsetRect( & tmpRect, 1, 1 ) ;
  1197.     tmpRect.right = theFrame.left + numPixels ;
  1198.  
  1199.     /* lock the compositing GWorld for updates */
  1200.     LockPixels(GetGWorldPixMap((**theInfo).thePBGWorld)) ;
  1201.  
  1202.     /* what do we want to draw today */
  1203.     if( numPixels <= 8 )
  1204.     {
  1205.         /* we don't start doing the 3d effect until we have enough pixels for the
  1206.          * start and end caps, so before that just draw a blue rect.
  1207.          */
  1208.         RGBForeColor( &RGBBlue ) ;
  1209.         PaintRect(&tmpRect) ;
  1210.         RGBForeColor( &RGBBlack ) ;
  1211.     }    
  1212.     else
  1213.     {
  1214.         short startLine = tmpRect.top ;
  1215.         
  1216.         /* draw the line gradation */
  1217.         MoveTo( tmpRect.left, startLine ) ;
  1218.         RGBForeColor( &RGBDkBlue ) ;
  1219.         LineTo( tmpRect.right, startLine++) ;
  1220.         
  1221.         MoveTo( tmpRect.left, startLine ) ;
  1222.         RGBForeColor( &RGBMedBlue ) ;
  1223.         LineTo( tmpRect.right, startLine++) ;
  1224.         
  1225.         MoveTo( tmpRect.left, startLine ) ;
  1226.         RGBForeColor( &RGBBlue ) ;
  1227.         LineTo( tmpRect.right, startLine++) ;
  1228.         
  1229.         MoveTo( tmpRect.left, startLine ) ;
  1230.         RGBForeColor( &RGBLtBlue ) ;
  1231.         LineTo( tmpRect.right, startLine++) ;
  1232.         
  1233.         MoveTo( tmpRect.left, startLine ) ;
  1234.         RGBForeColor( &RGBWhite ) ;
  1235.         LineTo( tmpRect.right, startLine++) ;
  1236.         
  1237.         MoveTo( tmpRect.left, startLine ) ;
  1238.         RGBForeColor( &RGBLtBlue ) ;
  1239.         LineTo( tmpRect.right, startLine++) ;
  1240.         
  1241.         MoveTo( tmpRect.left, startLine ) ;
  1242.         RGBForeColor( &RGBBlue ) ;
  1243.         LineTo( tmpRect.right, startLine++) ;
  1244.         
  1245.         MoveTo( tmpRect.left, startLine ) ;
  1246.         RGBForeColor( &RGBMedBlue ) ;
  1247.         LineTo( tmpRect.right, startLine++) ;
  1248.         
  1249.         MoveTo( tmpRect.left, startLine ) ;
  1250.         RGBForeColor( &RGBDkBlue ) ;
  1251.         LineTo( tmpRect.right, startLine++) ;
  1252.         
  1253.         MoveTo( tmpRect.left, startLine ) ;
  1254.         RGBForeColor( &RGBBlack ) ;
  1255.         LineTo( tmpRect.right, startLine++) ;
  1256.         
  1257.         if( theStartCap != NULL )
  1258.         {
  1259.             destRect.top = theStartCap->portRect.top ;
  1260.             destRect.left = theStartCap->portRect.left ;
  1261.             destRect.bottom = theStartCap->portRect.bottom ;
  1262.             destRect.right = theStartCap->portRect.right ;
  1263.             
  1264.             OffsetRect(&destRect, 2, 2) ;
  1265.             
  1266.             LockPixels(GetGWorldPixMap(theStartCap)) ;        
  1267.             CopyBits(    (BitMapPtr) &theStartCap->portPixMap, 
  1268.                         (BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, 
  1269.                         & theStartCap->portRect, 
  1270.                         & destRect, 
  1271.                         srcCopy, 
  1272.                         0L ) ;
  1273.             UnlockPixels(GetGWorldPixMap(theStartCap)) ;        
  1274.         }
  1275.         
  1276.         if( theEndCap != NULL )
  1277.         {
  1278.             destRect.top = theEndCap->portRect.top ;
  1279.             destRect.left = theEndCap->portRect.left ;
  1280.             destRect.bottom = theEndCap->portRect.bottom ;
  1281.             destRect.right = theEndCap->portRect.right ;
  1282.             
  1283.             OffsetRect(&destRect, numPixels + 2 - 6 , 2) ;
  1284.             
  1285.             LockPixels(GetGWorldPixMap(theEndCap)) ;        
  1286.             CopyBits(    (BitMapPtr) &theEndCap->portPixMap, 
  1287.                         (BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, 
  1288.                         & theEndCap->portRect, 
  1289.                         & destRect, 
  1290.                         srcCopy, 
  1291.                         0L ) ;
  1292.             UnlockPixels(GetGWorldPixMap(theEndCap)) ;        
  1293.         }
  1294.     }    
  1295.             
  1296.     
  1297.     /* handle the drop shadow */
  1298.     if( numPixels > 3 && theDropShadow != NULL )
  1299.     {
  1300.         destRect.top = theDropShadow->portRect.top ;
  1301.         destRect.left = theDropShadow->portRect.left ;
  1302.         destRect.bottom = theDropShadow->portRect.bottom ;
  1303.         destRect.right = theDropShadow->portRect.right ;
  1304.         
  1305.         OffsetRect(&destRect, numPixels + 2 - 3, 2) ;
  1306.         
  1307.         LockPixels(GetGWorldPixMap(theDropShadow)) ;        
  1308.         CopyBits(    (BitMapPtr) &theDropShadow->portPixMap, 
  1309.                     (BitMapPtr) &((**theInfo).thePBGWorld->portPixMap), 
  1310.                     & theDropShadow->portRect, 
  1311.                     & destRect, 
  1312.                     srcCopy, 
  1313.                     0L ) ;
  1314.         UnlockPixels(GetGWorldPixMap(theDropShadow)) ;        
  1315.     }
  1316.     
  1317.     
  1318.     SetGWorld( savedPort, gdh ) ;
  1319.         
  1320.     CopyBits(    (BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, 
  1321.                 &(**theInfo).thePBDialog->portBits, 
  1322.                 &(**theInfo).thePBGWorld->portRect, 
  1323.                 &(**theInfo).thePBRect, 
  1324.                 srcCopy, 
  1325.                 0L ) ;
  1326.         
  1327.     UnlockPixels(GetGWorldPixMap((**theInfo).thePBGWorld)) ;
  1328.     
  1329.     HUnlock((Handle)theInfo) ;
  1330. }
  1331.  
  1332.  
  1333. /*------------------------------------------------------------ */
  1334.  
  1335. /*
  1336.  * free up a progress bar info record
  1337.  */
  1338. void    PB_Delete( ProgressBarDlogInfoHdl theInfo ) 
  1339. {
  1340.     GWorldPtr    theGWorld ;
  1341.     
  1342.     /* dispose of the GWorld associated with the info record */
  1343.     if((theGWorld = (**theInfo).thePBGWorld ) != NULL )
  1344.         DisposeGWorld( theGWorld ) ;
  1345.     
  1346.     
  1347.     /* 
  1348.      * dispose of the memory allocated for the picts used to 
  1349.      * build the progress bar first make sure we have the 
  1350.      * requisite pict's loaded 
  1351.      */
  1352.     if(theStartCap == NULL )
  1353.         DisposeGWorld( theStartCap ) ;
  1354.         
  1355.     if(theEndCap == NULL )
  1356.         DisposeGWorld( theEndCap ) ;
  1357.         
  1358.     if(theDropShadow == NULL )
  1359.         DisposeGWorld( theDropShadow ) ;
  1360.         
  1361.     /* last of all blow away the info record */
  1362.     DisposeHandle((Handle)theInfo) ;
  1363. }
  1364.  
  1365.  
  1366.  
  1367. /* printing support */
  1368.  
  1369.  
  1370.  
  1371. /*---------------------------------------------------------------------*/
  1372.  
  1373. /*
  1374.  * SetupPrintHdl - This routine returns a default print handle for the 
  1375.  * current printer driver.
  1376.  *
  1377.  * The printer driver is expected to be closed upon entry, and is 
  1378.  * therefore opened and closed in this routine.
  1379.  */
  1380.  
  1381. OSErr SetupPrintHdl(THPrint *hPrint)
  1382. {
  1383.     OSErr err;
  1384.     
  1385.     /*
  1386.      * Create a handle, open the printer driver, set the
  1387.      * default values for the handle, and close the driver.
  1388.      * Be on the lookout for errors.
  1389.      */
  1390.  
  1391.     *hPrint = (THPrint) NewHandle(sizeof(TPrint));
  1392.  
  1393.     if ( *hPrint != NULL )
  1394.     {
  1395.         PrOpen() ;
  1396.  
  1397.         err = PrError() ;
  1398.                 
  1399.         if (err == noErr) 
  1400.         {
  1401.             PrintDefault( *hPrint ) ;
  1402.             err = PrError() ;
  1403.         }
  1404.  
  1405.         PrClose() ;
  1406.  
  1407.     }
  1408.     else
  1409.         err = MemError() ;
  1410.     
  1411.     return err;
  1412. }
  1413.  
  1414. void DoCreatePrintRecord( DocumentHdl theDocument )
  1415. {
  1416.     Boolean            changed = false ;
  1417.     char            theState = 0 ;
  1418.     short            theResRef ;
  1419.     FSSpec             theFile ;
  1420.     
  1421.     /*  create a new print record */
  1422.     theState = HGetState( (Handle)theDocument ) ;
  1423.     MoveHHi( (Handle)theDocument ) ;
  1424.     HLock( (Handle)theDocument ) ;
  1425.     
  1426.     if(SetupPrintHdl( &(**theDocument).fPrintRec ) == noErr) 
  1427.     {        
  1428.         /*  check we have a "good" print record */
  1429.         changed = PrValidate( (**theDocument).fPrintRec ) ;
  1430.         
  1431.     }
  1432.     HSetState( (Handle)theDocument, theState ) ;
  1433. }
  1434.  
  1435. /* ---------------------------------------------------------------------------------- */
  1436.  
  1437. OSErr DoStyleDlog(THPrint hPrint)
  1438. {
  1439.     OSErr    err = noErr ;
  1440.     Boolean    changed = false ;
  1441.     
  1442.     PrOpen() ;
  1443.     if((err = PrError()) == noErr ) {
  1444.         changed = PrStlDialog(hPrint);
  1445.         err = PrError();
  1446.         if (!err && !changed) err = iPrAbort;
  1447.     }
  1448.  
  1449.     PrClose();
  1450.     
  1451.     return err;
  1452. }
  1453.  
  1454. /* ---------------------------------------------------------------------------------- */
  1455.  
  1456. OSErr DoJobDlog(THPrint hPrint)
  1457. {
  1458.     OSErr    err = noErr ;
  1459.     Boolean    changed = false ;
  1460.     
  1461.     PrOpen() ;
  1462.     if((err = PrError()) == noErr ) {
  1463.         changed = PrJobDialog(hPrint);
  1464.         err = PrError();
  1465.         if (!err && !changed) err = iPrAbort;
  1466.     }
  1467.  
  1468.     PrClose();
  1469.     
  1470.     return err;
  1471. }
  1472.  
  1473. /* ---------------------------------------------------------------------------------- */
  1474. /*   CommandPeriod - This routine checks to see if the user has */
  1475. /*   pressed command-period.  The Printing Manager does this */
  1476. /*   for us, but a routine like this is helpful to allow users */
  1477. /*   to cancel in the middle of a rendering routine, rather */
  1478. /*   than only Printing Manager operations. */
  1479. /*    */
  1480. /*   If there's a command-period in the event queue, the */
  1481. /*   routine returns iPrAbort just like the Printing Manager. */
  1482. /*   Otherwise, it returns noErr. */
  1483.  
  1484. OSErr CommandPeriod()
  1485. {
  1486.     Boolean        cancel = false;
  1487.     EventRecord    evtRec;
  1488.     
  1489.     while (!cancel && (WaitNextEvent(keyDownMask | autoKeyMask, &evtRec, 0, NULL)))
  1490.         cancel = (evtRec.modifiers & cmdKey) &&
  1491.                  ((evtRec.message & charCodeMask) == '.');
  1492.  
  1493.     return ((cancel)? iPrAbort: noErr);
  1494. }
  1495.  
  1496. /* ---------------------------------------------------------------------------------- */
  1497. /*  IdleProc - This routine is a PrIdleProcPtr that spins our */
  1498. /*   cursor and looks for command-period presses during */
  1499. /*   printing. */
  1500.  
  1501.  
  1502. pascal void IdleProc()
  1503. {
  1504.     OSErr        err;
  1505. //    BumpCursor();
  1506.     if (err = CommandPeriod()) 
  1507.         PrSetError(err);
  1508. }
  1509. /* ---------------------------------------------------------------------------------- */
  1510. short    GeneralCountPages( 
  1511.     GWorldPtr    theGWorld, 
  1512.     Rect         *pageRect ) 
  1513. {
  1514.     Rect            pictRect ;
  1515.     short            horizOffset, 
  1516.                     vertOffset,
  1517.                     pagesWide = 0,     /*  the number of pages wide the image is */
  1518.                     pagesHigh = 0,     /*  the number pages high for this image */
  1519.                     pageWidth,         /*  the width of one page */
  1520.                     pageHeight ;    /*  the height of one page */
  1521.  
  1522.     DocumentHdl        theDocumentHdl ;
  1523.     PictDataHdl        thePictDataHdl ;
  1524.     OSErr            theErr ;
  1525.  
  1526.     pictRect = theGWorld->portRect ;
  1527.     
  1528.     horizOffset = -(pictRect.left) ;
  1529.     vertOffset = -(pictRect.top) ;
  1530.     
  1531.     OffsetRect( &pictRect, horizOffset, vertOffset ) ;    /*  this should make the origin of the rect (0,0) */
  1532.  
  1533.     pageWidth = pageRect->right - pageRect->left ;
  1534.     pageHeight = pageRect->bottom - pageRect->top ;
  1535.     
  1536.     pagesWide = (1.0 + pictRect.right / pageWidth ) ;    /*  round up the number of pages to the nearest */
  1537.     pagesHigh = (1.0 + pictRect.top  / pageHeight ) ;    /*  whole page in each direction. */
  1538.  
  1539.     return pagesWide * pagesHigh ;
  1540. }
  1541.  
  1542. /* ---------------------------------------------------------------------------------- */
  1543.  
  1544. void    GeneralPrintPage( 
  1545.     GWorldPtr         theGWorld, 
  1546.     Rect             *pageRect, 
  1547.     GrafPtr         imagingPort, 
  1548.     short             pageNum ) 
  1549. {
  1550.     GWorldPtr        docGWorld;
  1551.     Rect            pictRect, rectToPrint,srcRect,dstRect;
  1552.     short            pagesWide,         /*  the number of pages wide the image is */
  1553.                     pagesHigh,         /*  the number pages high for this image */
  1554.                     horozTile,         /*  used in the loop to denote the H tile to print from the image */
  1555.                     vertTile ;         /*  used in the loop to denote the V tile to print from the image */
  1556.     short            thisPage = 1;    /*  used to find the page they want us to print */
  1557.     short            pictHOff,
  1558.                     pictVOff,
  1559.                     pictWidth,         /*  the width of the doc's GWorld */
  1560.                     pictHeight ;    /*  the height of the doc's GWorld */
  1561.     short            pageWidth,         /*  the width of one page */
  1562.                     pageHeight ;    /*  the height of one page */
  1563.     DocumentHdl        theDocumentHdl ;
  1564.     PictDataHdl        thePictDataHdl ;
  1565.     OSErr            theErr ;
  1566.     PixMapHandle    offPixMap ;
  1567.  
  1568.     pictRect = theGWorld->portRect ;
  1569.     
  1570.     SetPort( imagingPort ) ;
  1571.     
  1572.     pictHOff   = -(pictRect.left) ;
  1573.     pictVOff   = -(pictRect.top) ;
  1574.     pictWidth  = pictRect.right - pictRect.left ;
  1575.     pictHeight = pictRect.bottom - pictRect.top ;
  1576.     
  1577.     pageWidth = pageRect->right - pageRect->left ;
  1578.     pageHeight = pageRect->bottom - pageRect->top ;
  1579.     
  1580.     pagesWide = (1.0 + pictWidth  / pageWidth  ) ;    /*  round up the number of pages to the nearest */
  1581.     pagesHigh = (1.0 + pictHeight / pageHeight ) ;    /*  whole page in each direction. */
  1582.     
  1583.     thisPage = 1;
  1584.     for (vertTile=0; vertTile<pagesHigh; vertTile++)
  1585.     {
  1586.         for (horozTile=0; horozTile<pagesWide; horozTile++)
  1587.         {
  1588.         
  1589.             /*  check this is the page we were called to print */
  1590.             
  1591.             if( thisPage == pageNum )
  1592.             {
  1593.                 srcRect = *pageRect;
  1594.                 
  1595.                 OffsetRect( &srcRect,
  1596.                             pictRect.left - srcRect.left,
  1597.                             pictRect.top  - srcRect.top );
  1598.                     
  1599.                 OffsetRect( &srcRect,
  1600.                             horozTile * pageWidth,
  1601.                             vertTile * pageHeight );
  1602.                 
  1603.                 SectRect( &srcRect, &pictRect, &srcRect);
  1604.                 
  1605.  
  1606.                 /*  finess the rect to print, we'll assume the the top left is always correct. */
  1607.                 /*  this helps with areas of the pict that don't fit entirely on one sheet of */
  1608.                 /*  paper */
  1609.                 
  1610.                 dstRect = srcRect;
  1611.                 
  1612.                 OffsetRect( &dstRect,
  1613.                             pageRect->left - srcRect.left,
  1614.                             pageRect->top  - srcRect.top );
  1615.  
  1616.                 ClipRect( &dstRect ) ;
  1617.                 
  1618.                 /* get the gworld pixmap and lock it down */
  1619.                 offPixMap = GetGWorldPixMap( theGWorld ) ;
  1620.                 (void) LockPixels( offPixMap ) ;
  1621.                 
  1622.                 /* copy from the gWorld Image to the window's port */
  1623.                 CopyBits( (BitMap *) *offPixMap,
  1624.                           &imagingPort->portBits,
  1625.                           &srcRect,                         
  1626.                           &dstRect,
  1627.                           srcCopy,
  1628.                           NULL ) ;
  1629.                 
  1630.                 /* unlock the pixmap */
  1631.                 (void) UnlockPixels( offPixMap ) ;
  1632.  
  1633.             }
  1634.             
  1635.             /*  bump the page number */
  1636.             thisPage++ ;
  1637.         }
  1638.     }
  1639.         
  1640. }
  1641.  
  1642. /* ---------------------------------------------------------------------------------- */
  1643.  
  1644. OSErr DoPrintLoop( WindowPtr    theWindow ) 
  1645. {
  1646.     short                savedResFile = CurResFile() ;
  1647.     GrafPtr                savedPort ;
  1648.     TPPrPort            printingPort ;
  1649.     OSErr                theErr = noErr ;
  1650.     THPrint                thePrintRec  ;
  1651.     PrIdleUPP            myIdleProc = NewPrIdleProc(IdleProc) ;
  1652.     DocumentHdl         theDocumentHdl ;
  1653.     CountPagesProc        countPagesP ;
  1654.     PrintPageProc        printPageP ;
  1655.     
  1656.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  1657.     if(theDocumentHdl != NULL)
  1658.     {
  1659.         
  1660.         thePrintRec = (**theDocumentHdl).fPrintRec ; 
  1661.         
  1662.         GetPort( &savedPort ) ;
  1663.         PrOpen() ;
  1664.         
  1665.         if( (theErr = PrError()) == noErr ) {
  1666.         
  1667.             short    numCopies = (**thePrintRec).prJob.iCopies ;
  1668.             short    firstPage = (**thePrintRec).prJob.iFstPage ;    /*  save the first page */
  1669.             short    lastPage = (**thePrintRec).prJob.iLstPage;        /*  save the last page */
  1670.             short    copies, pageNum ;
  1671.             
  1672.             (**thePrintRec).prJob.iFstPage = 1 ;            /*  reset to 1 */
  1673.             (**thePrintRec).prJob.iLstPage = iPrPgMax ;    /*  reset to maximum */
  1674.  
  1675.             /*  we don't assign this directly because NewPrIdleProc may move memory, */
  1676.             /*  so assign to an intermediate - myIdleProc */
  1677.             (**thePrintRec).prJob.pIdleProc =  myIdleProc; /*  install the cursor spinning idle proc */
  1678.             
  1679.             /*
  1680.              * since the count pages function is dereferenced by a pointer we have two choices,
  1681.              * either lock the handle, or copy the function pointer.
  1682.              */
  1683.             countPagesP = (**theDocumentHdl).procs->countPagesP ;
  1684.             
  1685.             /* if there is one, call the save handling proc with this window */
  1686.             if( countPagesP )
  1687.                 lastPage = (*countPagesP)( theWindow, &(**thePrintRec).prInfo.rPage ) ;
  1688.             
  1689.             for( copies = 1; copies <= numCopies ; copies++ ) {
  1690.             
  1691.                 printingPort = PrOpenDoc( thePrintRec, NULL, NULL ) ;
  1692.                 SetPort( (GrafPtr)printingPort ) ;
  1693.                 if((theErr = PrError()) == noErr ) {
  1694.                 
  1695.                     for( pageNum = firstPage; pageNum <= lastPage; pageNum++ ) {
  1696.                     
  1697.                         PrOpenPage( printingPort, NULL ) ;
  1698.                         if((theErr = PrError()) == noErr ) {
  1699.                             
  1700.                             /*
  1701.                              * since the print page function is dereferenced by a pointer 
  1702.                              * we have two choices, either lock the handle, or copy the 
  1703.                              * function pointer.
  1704.                              */
  1705.                             printPageP = (**theDocumentHdl).procs->printPageP ;
  1706.                             
  1707.                             /*  image the page */
  1708.                             if( printPageP )
  1709.                                 (*printPageP)( theWindow,  &(**thePrintRec).prInfo.rPage, (GrafPtr)printingPort, pageNum  ) ;
  1710.             
  1711.                             PrClosePage(printingPort) ;
  1712.                         }
  1713.                     
  1714.                     }
  1715.                     if( (theErr = PrError()) == noErr ) {
  1716.  
  1717.                         TPrStatus         theStatus ;
  1718.  
  1719.                         PrCloseDoc(printingPort) ;
  1720.                         theErr = PrError() ;
  1721.  
  1722.                         /*  if we're printing to our good friend the ImageWriter, or similar, despool */
  1723.                         if( theErr == noErr && ((**thePrintRec).prJob.bJDocLoop == bSpoolLoop))
  1724.                             PrPicFile( thePrintRec, NULL, NULL, NULL, &theStatus ) ; 
  1725.                     }
  1726.                 }
  1727.             }
  1728.         }
  1729.         PrClose() ;
  1730.  
  1731.         DisposeRoutineDescriptor((UniversalProcPtr)myIdleProc) ;
  1732.  
  1733.         SetPort( savedPort ) ;
  1734.     }
  1735.  
  1736.     return theErr ;
  1737.     
  1738. }
  1739.  
  1740.  
  1741. /*------------------------------------------------------------ */
  1742.  
  1743. /*
  1744.  * called to register our AppleEvent handlers.
  1745.  *
  1746.  * Should really have some error handling in here.
  1747.  */
  1748. void RegisterRequiredAppleEventHandlers(void)
  1749. {
  1750.     OSErr                 theError;
  1751.     ProcessSerialNumber    myApplicationPSN;            /* This application's psn  */
  1752.     
  1753.     /* Set up a self-addressed descriptor record.  */
  1754.      myApplicationPSN.highLongOfPSN = 0;
  1755.      myApplicationPSN.lowLongOfPSN = kCurrentProcess ;
  1756.      
  1757.      theError = AECreateDesc(typeProcessSerialNumber,
  1758.                              (Ptr)&myApplicationPSN,
  1759.                              sizeof(ProcessSerialNumber),
  1760.                              &gSelfAddress);
  1761.     if (theError!=noErr)
  1762.         return;
  1763.     
  1764.     theError = AEInstallEventHandler(    kCoreEventClass,
  1765.                                         kAEOpenApplication,
  1766.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypeOAPP),
  1767.                                         0L,
  1768.                                         false);
  1769.     if (theError!=noErr)
  1770.         return;
  1771.                 
  1772.     theError = AEInstallEventHandler(    kCoreEventClass,
  1773.                                         kAEOpenDocuments,
  1774.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypeODOC),
  1775.                                         0L,
  1776.                                         false);
  1777.     if (theError!=noErr)
  1778.         return;
  1779.                 
  1780.     theError = AEInstallEventHandler(    kCoreEventClass,
  1781.                                         kAEPrintDocuments,
  1782.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypePDOC),
  1783.                                         0L,
  1784.                                         false);
  1785.     if (theError!=noErr)
  1786.         return;
  1787.                 
  1788.     theError = AEInstallEventHandler(    kCoreEventClass,
  1789.                                         kAEQuitApplication,
  1790.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypeQUIT),
  1791.                                         0L,
  1792.                                         false);
  1793.     if (theError!=noErr)
  1794.         return;
  1795. }
  1796.  
  1797.  
  1798. /*------------------------------------------------------------ */
  1799.  
  1800. /*
  1801.  * open application theEventRecord handler for the core theEventRecord suite, 
  1802.  * by default we just want a blank new document
  1803.  */
  1804. pascal OSErr HandleCoreAppleEventOfTypeOAPP( AppleEvent *theAppleEvent, AppleEvent *theAppleEventReply, long userDefinedReferenceConstant)
  1805. {
  1806.     /*
  1807.      * we don't actually do anything on open - you could,
  1808.      * for example you might want to open a blank untitled 
  1809.      * theWindow
  1810.      */
  1811.     OSErr theError = noErr ;
  1812.     return theError;
  1813. }
  1814.  
  1815.  
  1816. /*------------------------------------------------------------ */
  1817.  
  1818. /*
  1819.  * handler for the open document AppleEvent handler
  1820.  */
  1821.  
  1822. pascal OSErr HandleCoreAppleEventOfTypeODOC(AppleEvent *theAppleEvent, AppleEvent *theAppleEventReply, long userDefinedReferenceConstant)
  1823. {
  1824.     FSSpec         theFileSpec;
  1825.     AEDescList    theDocumentList;
  1826.     OSErr        theError,
  1827.                 theIgnoredError;
  1828.     long        myTempIndex,
  1829.                 numberOfItemsInList;
  1830.     Size         actualSize;
  1831.     AEKeyword    theAEKeyword;
  1832.     DescType    theDescriptorType;
  1833.  
  1834.     
  1835.     theError = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&theDocumentList);
  1836.     if (theError == noErr) {
  1837.         /*
  1838.          * see how many descriptor items are in the list
  1839.          * this is the number of documents we want to open
  1840.          */
  1841.         theError = AECountItems(&theDocumentList,&numberOfItemsInList);
  1842.         
  1843.         /*
  1844.          * now get each descriptor record from the list
  1845.          * coerce the returned data to an FSSpec record, and
  1846.          * open the asoociated file
  1847.          */
  1848.         for (myTempIndex=1; myTempIndex <= numberOfItemsInList && theError == noErr; myTempIndex++) {
  1849.         
  1850.             theError = AEGetNthPtr(    &theDocumentList, 
  1851.                                     myTempIndex,
  1852.                                     typeFSS,
  1853.                                     &theAEKeyword,
  1854.                                     &theDescriptorType,
  1855.                                     (Ptr)&theFileSpec,
  1856.                                     sizeof(theFileSpec),
  1857.                                     &actualSize);
  1858.     
  1859.             if (theError == noErr)    {
  1860.             
  1861.                 FInfo        fndrInfo ;
  1862.                 
  1863.                 /*
  1864.                  * we now have a valid FSSpec to reference the file, we need to know 
  1865.                  * what type the file is to determine which file open function to call
  1866.                  * we can determine this from the finder info for the file
  1867.                  */
  1868.                 
  1869.                 theError = FSpGetFInfo( &theFileSpec, &fndrInfo );    
  1870.                 
  1871.                 /*
  1872.                  * if we got that ok, then we switch on the file  
  1873.                  * type (we don't care about the creator type)    
  1874.                  */
  1875.                         
  1876.                 if (theError == noErr)    {
  1877.                 
  1878.                     switch( fndrInfo.fdType ) {
  1879.                         case 'TEXT':    /* your app should NOT really open text files since
  1880.                                          * they may not be of type 3DMF, this is here for 
  1881.                                          * debugging, note that the standard file dlog will
  1882.                                          * not allow you to open TEXT files.
  1883.                                          */
  1884.                         case '3DMF':
  1885.                             ViewerWindow_Open( &theFileSpec );
  1886.                             break ;
  1887.                     }
  1888.                 }
  1889.             }
  1890.         }
  1891.         theIgnoredError = AEDisposeDesc(&theDocumentList);
  1892.     }
  1893.     return theError ;
  1894. }
  1895.  
  1896. /*------------------------------------------------------------ */
  1897.  
  1898. /*
  1899.  * handler for the print document theEventRecord handler
  1900.  */
  1901. pascal OSErr HandleCoreAppleEventOfTypePDOC(AppleEvent *theAppleEvent,AppleEvent *theAppleEventReply,long userDefinedReferenceConstant)
  1902. {
  1903.     FSSpec         theFileSpec;
  1904.     AEDescList    theDocumentList;
  1905.     OSErr        theError;
  1906.     long        myTempIndex,
  1907.                 numberOfItemsInList;
  1908.     Size         actualSize;
  1909.     AEKeyword    theAEKeyword;
  1910.     DescType    theDescriptorType;
  1911.  
  1912.     
  1913.     theError = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&theDocumentList);
  1914.     if (theError == noErr) {    
  1915.         
  1916.         /*
  1917.          * see how many descriptor items are in the list
  1918.          * this is the number of documents we want to print
  1919.          */
  1920.         
  1921.         theError = AECountItems(&theDocumentList,&numberOfItemsInList);
  1922.  
  1923.         /*
  1924.          * now get each descriptor record from the list
  1925.          * coerce the returned data to an FSSpec record, and
  1926.          * print the asoociated file
  1927.          */
  1928.         
  1929.         for (myTempIndex=1; myTempIndex <= numberOfItemsInList && theError == noErr; myTempIndex++) {
  1930.         
  1931.             theError = AEGetNthPtr(    &theDocumentList, 
  1932.                                 myTempIndex,
  1933.                                 typeFSS,
  1934.                                 &theAEKeyword,
  1935.                                 &theDescriptorType,
  1936.                                 (Ptr)&theFileSpec,
  1937.                                 sizeof(theFileSpec),
  1938.                                 &actualSize);
  1939.     
  1940.             if (theError == noErr)    {    
  1941.                             
  1942.                 /*
  1943.                  * if the app handles printing then you could do 
  1944.                  * something like: theError = HandlePrintDoc( &theFileSpec );
  1945.                  */
  1946.                 
  1947.                 theError = errAEEventNotHandled ;
  1948.             }
  1949.         }
  1950.         theError = AEDisposeDesc(&theDocumentList);
  1951.     }
  1952.     return theError ;
  1953. }
  1954.  
  1955. /*------------------------------------------------------------ */
  1956.  
  1957. /*
  1958.  * Quit AppleEvent handler
  1959.  */
  1960.  
  1961. pascal OSErr HandleCoreAppleEventOfTypeQUIT(AppleEvent *theAppleEvent,AppleEvent *theAppleEventReply,long userDefinedReferenceConstant)
  1962. {
  1963.     OSErr             theError = noErr ;        /* this is used as the return value  */
  1964.  
  1965.     theError = HandleFileQuitItem() ;
  1966.             
  1967.     return theError ;
  1968. }
  1969.  
  1970. /*------------------------------------------------------------ */
  1971.  
  1972. /*
  1973.  * we want to handle events until the fronmost theWindow goes away
  1974.  */
  1975.  
  1976. void MainEventLoop( void )
  1977. {
  1978.     EventRecord     theEventRecord;
  1979.  
  1980.     while( !gQuitFlag )
  1981.     {
  1982.         Point            mouseLoc ;
  1983.         
  1984.         if (WaitNextEvent( everyEvent, &theEventRecord,  GetCaretTime(), NULL ))
  1985.         {
  1986.             AdjustMenus() ;
  1987.             ( void ) HandleEvent( &theEventRecord ) ;
  1988.         }
  1989.     }
  1990. }
  1991.  
  1992. /*------------------------------------------------------------ */
  1993.  
  1994. /*
  1995.  * actually handle the event, this function can also be used for 
  1996.  * the anchor for the renderer.
  1997.  */
  1998.  
  1999.  
  2000. TQ3Boolean HandleEvent( const EventRecord *theEventRecord )
  2001. {
  2002.     WindowPtr           theWindow;
  2003.     GrafPtr                savedPort ;
  2004.     short               thePart;
  2005.     Rect                screenRect;
  2006.     Rect                growRect ;
  2007.     Point                aPoint = {100, 100};
  2008.     GrafPtr                oldPort ;
  2009.     Boolean                eventWasHandled = false ;
  2010.     unsigned long        width ;
  2011.     unsigned long        height ;
  2012.     long                newSize ;
  2013.     OSErr                theErr ;
  2014.     Point                mouseLoc ;
  2015.     TQ3Boolean             handledEvent = kQ3False ;
  2016.     TQ3ViewerObject        theViewer = NULL ;
  2017.     ViewerDataHdl        theViewerDataHdl ;
  2018.     DocumentHdl            theDocumentHdl ;
  2019.     UpdateContentProc    theUpdateProc ;
  2020.     HandleEventProc        theEventProc ;
  2021.     CloseProc            closeP ;
  2022.         
  2023.     SetCursor( &qd.arrow ) ;
  2024.             
  2025.     switch (theEventRecord->what) 
  2026.     {
  2027.         case mouseDown:
  2028.         
  2029.             /* we set up thePart in the window test at the top of this routine */
  2030.             thePart = FindWindow ( theEventRecord->where, &theWindow ) ;
  2031.  
  2032.             switch( thePart ) {
  2033.                 case inMenuBar: 
  2034.                     HandleMenuCommand(MenuSelect(theEventRecord->where));
  2035.                     handledEvent = kQ3True ;
  2036.                     break;
  2037.                 
  2038.                 case inDrag:
  2039.             
  2040.                     screenRect = (**GetGrayRgn()).rgnBBox;
  2041.                     DragWindow( theWindow, theEventRecord->where, &screenRect );
  2042.                     handledEvent = kQ3True ;
  2043.                     break ;
  2044.             
  2045.                 case inContent:
  2046.             
  2047.                     if (theWindow != FrontWindow()) 
  2048.                     {
  2049.                         SelectWindow( theWindow );
  2050.                         handledEvent = kQ3True ;
  2051.                     }
  2052.                     else
  2053.                     {
  2054.                         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2055.                         
  2056.                         /*
  2057.                          * since the update function is dereferenced by a pointer we have two choices,
  2058.                          * either lock the handle, or copy the function pointer.
  2059.                          */
  2060.                         theEventProc = (**theDocumentHdl).procs->handleEventP ;
  2061.                         
  2062.                         /* if there is one, call the event handling proc with this window */
  2063.                         if( theEventProc )
  2064.                             handledEvent = (*theEventProc)( theWindow, theEventRecord ) ;
  2065.                         else
  2066.                             handledEvent = kQ3False ;
  2067.                     }
  2068.                     break ;
  2069.             
  2070.                 case inGrow:
  2071.                 
  2072.                     /*
  2073.                      * get the viewer object associated with this window
  2074.                      */
  2075.                     
  2076.                     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2077.                     if(theDocumentHdl != NULL) 
  2078.                     {
  2079.                         if((**theDocumentHdl).fDocumentMagic == kViewerMagic 
  2080.                             && (theViewerDataHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL
  2081.                             && (theViewer = (**theViewerDataHdl).fViewer) != NULL )
  2082.                         {
  2083.                             
  2084.                             /* 
  2085.                              * first we need to calculate the minimum size 
  2086.                              * for this viewer window, fortunately the
  2087.                              * viewer library has a handy little utility
  2088.                              * function that we can use here:
  2089.                              */
  2090.                             
  2091.                             
  2092.                             GetPort( &savedPort ) ;
  2093.                             SetPort( (GrafPtr)theWindow ) ;
  2094.                             
  2095.                             theErr = Q3ViewerGetMinimumDimension( 
  2096.                                         theViewer,
  2097.                                         &width,
  2098.                                         &height );
  2099.  
  2100.                             growRect.top = height + LMGetMBarHeight() ; /* the height of tuhe title bar is the same as the height of the menu bar */
  2101.                             growRect.left = width + 34;        /* +34 so the grow box look neat */
  2102.                             growRect.bottom = kMaxHeight ;
  2103.                             growRect.right = kMaxWidth ;        
  2104.                             
  2105.                             newSize = GrowWindow(theWindow, theEventRecord->where, &growRect);
  2106.                             if (newSize != 0) {
  2107.                                 width = LoWrd(newSize) ;
  2108.                                 height = HiWrd(newSize) ;
  2109.                                 SizeWindow(theWindow, width, height, true);
  2110.                                 Q3ViewerSetBounds( theViewer, &theWindow->portRect ) ;
  2111.                                 
  2112.                                 EraseRect( &theWindow->portRect ) ;
  2113.                                 Q3ViewerDraw( theViewer ) ;
  2114.                                 DoDrawGrowIcon( theWindow ) ;
  2115.                                 
  2116.                             }
  2117.                             handledEvent = kQ3True ;
  2118.                             SetPort( savedPort ) ;
  2119.  
  2120.                         }
  2121.                     }
  2122.                     break;
  2123.                     
  2124.                 case inGoAway:
  2125.                     if (TrackGoAway( theWindow, theEventRecord->where )) {
  2126.                         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2127.                         closeP = (**theDocumentHdl).procs->closeP ;
  2128.                         if( closeP )
  2129.                             (*closeP)( theWindow ) ;
  2130.                     }
  2131.                     handledEvent = kQ3True ;
  2132.                     break ;
  2133.                     
  2134.                 default:
  2135.                     break ;
  2136.             }
  2137.             break ;
  2138.                     
  2139.                 
  2140.         case updateEvt:
  2141.  
  2142.             handledEvent = kQ3True  ;
  2143.  
  2144.             theWindow = (WindowPtr)theEventRecord->message;
  2145.             theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2146.             
  2147.             /*
  2148.              * since the update function is dereferenced by a pointer we have two choices,
  2149.              * either lock the handle, or copy the finction pointer.
  2150.              */
  2151.             theUpdateProc = (**theDocumentHdl).procs->updateWindowP ;
  2152.             
  2153.             /* call the update proc with this window */
  2154.             if( theUpdateProc )
  2155.                 (*theUpdateProc)(theWindow) ;
  2156.                 
  2157.             break ;
  2158.             
  2159.         case keyDown:
  2160.         case autoKey:
  2161.             HandleKeyPress(theEventRecord);
  2162.             handledEvent = kQ3True ;
  2163.             break ;
  2164.             
  2165.         case diskEvt:
  2166.             if ( HiWrd(theEventRecord->message) != noErr ) 
  2167.                 (void) DIBadMount(aPoint, theEventRecord->message) ;
  2168.             handledEvent = kQ3True ;
  2169.             break ;
  2170.             
  2171.         case osEvt:
  2172.         case activateEvt:
  2173.             handledEvent = kQ3False  ;
  2174.             break ;
  2175.  
  2176.         case kHighLevelEvent:
  2177.             AEProcessAppleEvent(theEventRecord);
  2178.             handledEvent = kQ3True ;
  2179.             break ;
  2180.     }
  2181.  
  2182. Done:
  2183.     return handledEvent ;
  2184. }
  2185.  
  2186.  
  2187. /*------------------------------------------------------------ */
  2188.  
  2189. /*
  2190.  * handle keydow events, all we do is dispatch to the 
  2191.  * menu handler if the command key is down, otherwise
  2192.  * the keypress is ignored.
  2193.  */
  2194.  
  2195. void HandleKeyPress(EventRecord *theEventRecord)
  2196. {
  2197.     char    key;
  2198.  
  2199.     key = theEventRecord->message & charCodeMask;
  2200.     
  2201.     /* check to see if we selected a menu  */
  2202.     if ( theEventRecord->modifiers & cmdKey ) {        /* Command key down?  */
  2203.         HandleMenuCommand(MenuKey(key));
  2204.     } 
  2205. }
  2206.  
  2207.  
  2208. /*------------------------------------------------------------ */
  2209.  
  2210. /*
  2211.  * handle menu commands
  2212.  */
  2213.  
  2214. void HandleMenuCommand(long menuResult)
  2215. {
  2216.     short        menuID;
  2217.     short        menuItem;
  2218.  
  2219.     menuID = HiWrd(menuResult);
  2220.     menuItem = LoWrd(menuResult);
  2221.  
  2222.     switch ( menuID ) {
  2223.     
  2224.         case mInteractiveRendererMenu:
  2225.             HandleInteractiveRendererMenu( menuItem ) ;
  2226.             break ;
  2227.             
  2228.         case mAppleMenu:
  2229.             HandleAppleMenu( menuItem ) ;
  2230.             break ;
  2231.             
  2232.         case mFileMenu:
  2233.             HandleFileMenu( menuItem ) ;
  2234.             break;
  2235.         
  2236.         case mEditMenu:
  2237.             HandleEditMenu( menuItem ) ;
  2238.             break ;
  2239.             
  2240.         case mViewMenu:
  2241.             HandleViewMenu( menuItem ) ;
  2242.             break ;
  2243.  
  2244.     }
  2245.     HiliteMenu(0);        // Unhighlight whatever MenuSelect or MenuKey hilited
  2246. }
  2247.  
  2248.  
  2249.  
  2250. /*------------------------------------------------------------ */
  2251.  
  2252. /*
  2253.  * handle menu commands in the apple menu
  2254.  */
  2255.  
  2256.  
  2257. void HandleAppleMenu( short menuItem )
  2258. {
  2259.     Str255        daName;
  2260.     DialogPtr    theDialog ; 
  2261.     short        itemHit ;
  2262.     
  2263.     switch ( menuItem ) {
  2264.         ModalFilterUPP         theProc ;
  2265.  
  2266.         case iAppleAboutItem:
  2267.             
  2268.             theDialog = GetNewDialog ( kAboutDialogID, NULL, (WindowPtr)-1 );
  2269.             
  2270.             GetStdFilterProc( &theProc ) ;
  2271.             SetDialogDefaultItem(theDialog, ok) ;
  2272.             do {
  2273.                 ModalDialog ( theProc, &itemHit );
  2274.             } while( itemHit != ok ) ;
  2275.             DisposDialog ( theDialog );
  2276.             
  2277.             break;
  2278.             
  2279.         default:
  2280.             GetItem(GetMHandle(mAppleMenu), menuItem, daName);
  2281.             (void) OpenDeskAcc(daName);
  2282.             break;
  2283.     }
  2284. }
  2285.  
  2286. /*------------------------------------------------------------ */
  2287.  
  2288. /*
  2289.  * handle menu commands in the file menu
  2290.  */
  2291.  
  2292.  
  2293. void HandleFileMenu( short menuItem )
  2294. {
  2295.     WindowPtr            theWindow ;
  2296.     StandardFileReply    theSFReply ;
  2297.     DocumentHdl            theDocumentHdl ;
  2298.     SaveAsProc            saveAsP ;
  2299.     SaveProc            saveP ;
  2300.     RevertProc            revertP ;
  2301.     CloseProc            closeP ;
  2302.     PrePrintProc        prePrintP ;
  2303.     PostPrintProc        postPrintP ;
  2304.  
  2305.     switch ( menuItem ) {
  2306.     
  2307.         case iFileNewItem:
  2308.         
  2309.             ViewerWindow_New( "\pViewer Window" ) ;
  2310.             break ;
  2311.     
  2312.         case iFileSaveAsItem:
  2313.         
  2314.             if( (theWindow = FrontWindow()) != NULL )
  2315.             {
  2316.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2317.                 
  2318.                 /*
  2319.                  * since the save function is dereferenced by a pointer we have two choices,
  2320.                  * either lock the handle, or copy the function pointer.
  2321.                  */
  2322.                 saveAsP = (**theDocumentHdl).procs->saveAsP ;
  2323.                 
  2324.                 /* if there is one, call the save handling proc with this window */
  2325.                 if( saveAsP )
  2326.                     (*saveAsP)( theWindow ) ;
  2327.                 
  2328.             }
  2329.             break ;
  2330.  
  2331.         case iFileSaveItem:
  2332.             if( (theWindow = FrontWindow()) != NULL )
  2333.             {
  2334.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2335.                 
  2336.                 /*
  2337.                  * since the save function is dereferenced by a pointer we have two choices,
  2338.                  * either lock the handle, or copy the function pointer.
  2339.                  */
  2340.                 saveP = (**theDocumentHdl).procs->saveP ;
  2341.                 
  2342.                 /* if there is one, call the save handling proc with this window */
  2343.                 if( saveP )
  2344.                     (*saveP)( theWindow ) ;
  2345.                 
  2346.             }
  2347.             break ;
  2348.             
  2349.         
  2350.         case iFileRevertItem:
  2351.             if( (theWindow = FrontWindow()) != NULL )
  2352.             {
  2353.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2354.                 
  2355.                 /*
  2356.                  * since the revert function is dereferenced by a pointer we have two choices,
  2357.                  * either lock the handle, or copy the function pointer.
  2358.                  */
  2359.                 revertP = (**theDocumentHdl).procs->revertP ;
  2360.                 
  2361.                 /* if there is one, call the revert handling proc with this window */
  2362.                 if( revertP )
  2363.                     (*revertP)( theWindow ) ;
  2364.                 
  2365.             }
  2366.             break ;
  2367.         
  2368.         /* these need to be converted */
  2369.         case iFilePageSetupItem:
  2370.             if( (theWindow = FrontWindow()) != NULL )
  2371.             {
  2372.                 THPrint        thePrintRec ;
  2373.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2374.                 
  2375.                 thePrintRec = (**theDocumentHdl).fPrintRec ;
  2376.                 DoStyleDlog( thePrintRec ) ;
  2377.             }
  2378.             break ;
  2379.         
  2380.         case iFilePrintItem:
  2381.             if( (theWindow = FrontWindow()) != NULL )
  2382.             {
  2383.                 THPrint        thePrintRec ;
  2384.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2385.                 
  2386.                 thePrintRec = (**theDocumentHdl).fPrintRec ;
  2387.                 if( DoJobDlog( thePrintRec ) == noErr )
  2388.                 {
  2389.                 
  2390.                     /*
  2391.                      * since the preprint function is dereferenced by a pointer we have two choices,
  2392.                      * either lock the handle, or copy the function pointer.
  2393.                      */
  2394.                     prePrintP = (**theDocumentHdl).procs->prePrintP ;
  2395.                     
  2396.                     /* if there is one, call the revert handling proc with this window */
  2397.                     if( prePrintP )
  2398.                         (*prePrintP)( theWindow ) ;
  2399.                         
  2400.                     DoPrintLoop( theWindow ) ;
  2401.                     
  2402.                     postPrintP = (**theDocumentHdl).procs->postPrintP ;
  2403.                     
  2404.                     /* if there is one, call the revert handling proc with this window */
  2405.                     if( postPrintP )
  2406.                         (*postPrintP)( theWindow ) ;
  2407.                 }
  2408.                 
  2409.             }
  2410.             break ;
  2411.                 
  2412.         case iFileOpenItem:
  2413.         
  2414.             /* currently we only open 3dmf files */
  2415.             /* Get the file name to open  */
  2416.             StandardGetFile( NULL, kNumTypes, kTypeList, &theSFReply ) ;
  2417.     
  2418.             /* did the user cancel?  */
  2419.             if(theSFReply.sfGood)
  2420.                 ViewerWindow_Open( &theSFReply.sfFile ) ; /* no - process the file  */
  2421.                 
  2422.             break ;
  2423.             
  2424.         case iFileCloseItem:
  2425.             if( (theWindow = FrontWindow()) != NULL )
  2426.             {
  2427.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2428.                 
  2429.                 /*
  2430.                  * since the revert function is dereferenced by a pointer we have two choices,
  2431.                  * either lock the handle, or copy the function pointer.
  2432.                  */
  2433.                 closeP = (**theDocumentHdl).procs->closeP ;
  2434.                 
  2435.                 /* if there is one, call the revert handling proc with this window */
  2436.                 if( closeP )
  2437.                     (*closeP)( theWindow ) ;
  2438.                 
  2439.             }
  2440.             break ;
  2441.             
  2442.         case iFileQuitItem:
  2443.             HandleFileQuitItem();
  2444.             break;
  2445.     }
  2446.  
  2447. }
  2448.  
  2449.  
  2450. /*------------------------------------------------------------ */
  2451.  
  2452.  
  2453. /*
  2454.  * handles the Quit menu item in the file menu
  2455.  */
  2456.  
  2457. OSErr HandleFileQuitItem( void ) 
  2458. {
  2459.     OSErr             theError = noErr ;        /* this is used as the return value  */
  2460.     WindowPtr        theWindow ;
  2461.     Boolean            tempQuitFlag = true ;
  2462.     CloseProc        closeP ;
  2463.     DocumentHdl        theDocumentHdl ;
  2464.  
  2465.     /*
  2466.      * if the application has any open windows, close them before 
  2467.      * tempQuitFlag.  Since the user may cancelduring the process of 
  2468.      * closing, make sure we don't quit the app, unless they can 
  2469.      * be closed
  2470.      */
  2471.     while(( theWindow = FrontWindow()) != NULL && tempQuitFlag )
  2472.     {
  2473.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2474.         
  2475.         /*
  2476.          * since the save function is dereferenced by a pointer we have two choices,
  2477.          * either lock the handle, or copy the function pointer.
  2478.          */
  2479.         closeP = (**theDocumentHdl).procs->closeP ;
  2480.         
  2481.         /* if there is one, call the save handling proc with this window */
  2482.         if( closeP )
  2483.             tempQuitFlag = ((*closeP)( theWindow ) == noErr)  ;            
  2484.     }
  2485.  
  2486.     /*
  2487.      * if we closed everything up successfully, return noErr, otherwise
  2488.      * indicate to the caller of this function that we canceled
  2489.      */
  2490.     
  2491.     if (tempQuitFlag) {
  2492.         gQuitFlag = true;                    /* in other word the user didn't cancel  */
  2493.          AEDisposeDesc(&gSelfAddress);        /* don't forget to dispose of the        */
  2494.     }
  2495.     else {
  2496.         theError = userCanceledErr ;
  2497.     }
  2498.     
  2499.     return theError ;
  2500.  
  2501. }
  2502.  
  2503. /*------------------------------------------------------------ */
  2504.  
  2505. /*
  2506.  * handle menu commands in the edit menu
  2507.  *
  2508.  * To Do: each menu command needs to be factored into the list of procs
  2509.  *        for the document type.
  2510.  */
  2511.  
  2512.  
  2513. void HandleEditMenu( short menuItem )
  2514. {
  2515.     DocumentHdl            theDocumentHdl ;
  2516.     ViewerDataHdl        theViewerHdl ;
  2517.  
  2518.     WindowPtr            theWindow ;
  2519.     TQ3ViewerObject        theViewer ;
  2520.     OSErr                theError ;
  2521.     GrafPtr                savedPort ;
  2522.     
  2523.     CutProc                cutProc ;            /* handle clipboard cut, same as copy followed by clear */
  2524.     CopyProc            copyProc ;            /* handle clipboard copy */
  2525.     PasteProc            pasteProc ;            /* paste compatible scrap type from the scrap */
  2526.     ClearProc            clearProc ;            /* clear the document contents without a save to the scrap */
  2527.     UndoProc            undoProc ;            /* undo the last action - if supported */
  2528.     
  2529.     /*
  2530.      * because we do this we are assuming that this menu is disabled for the
  2531.      * case where there is no window.
  2532.      */
  2533.     theWindow = FrontWindow() ;
  2534.     SetPort((GrafPtr)theWindow) ;
  2535.     if( theWindow != NULL )
  2536.     {
  2537.         long                 aLong ;
  2538.         
  2539.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2540.                 
  2541.         switch ( menuItem ) 
  2542.         {
  2543.             
  2544.             case iEditUndoItem:
  2545.                 undoProc = (**theDocumentHdl).procs->undoProc ;
  2546.                 /* if there is one, call the undo handling proc with this window */
  2547.                 if( undoProc )
  2548.                     (*undoProc)( theWindow ) ;
  2549.                 
  2550.                 /* redraw the content region of the window to reflect the change */
  2551.                 GetPort( &savedPort ) ;    
  2552.                 SetPort( theWindow ) ;
  2553.                 InvalRect( &theWindow->portRect ) ;
  2554.                 SetPort( savedPort ) ;
  2555.                 break ;
  2556.                 
  2557.             case iEditCutItem:
  2558.                 cutProc = (**theDocumentHdl).procs->cutProc ;
  2559.                 /* if there is one, call the cut handling proc with this window */
  2560.                 if( cutProc )
  2561.                     (*cutProc)( theWindow ) ;
  2562.                 aLong = UnloadScrap();
  2563.                 break ;
  2564.                 
  2565.             case iEditCopyItem:
  2566.                 copyProc = (**theDocumentHdl).procs->copyProc ;
  2567.                 /* if there is one, call the copy handling proc with this window */
  2568.                 if( copyProc )
  2569.                     (*copyProc)( theWindow ) ;
  2570.                 aLong = UnloadScrap();
  2571.                 break ;
  2572.                 
  2573.             case iEditPasteItem:
  2574.                 pasteProc = (**theDocumentHdl).procs->pasteProc ;
  2575.                 /* if there is one, call the paste handling proc with this window */
  2576.                 if( pasteProc )
  2577.                     (*pasteProc)( theWindow ) ;
  2578.                 aLong = UnloadScrap();
  2579.                 break ;
  2580.                 
  2581.             case iEditClearItem:
  2582.                 clearProc = (**theDocumentHdl).procs->clearProc ;
  2583.                 /* if there is one, call the clear handling proc with this window */
  2584.                 if( clearProc )
  2585.                     (*clearProc)( theWindow ) ;
  2586.                 aLong = UnloadScrap();
  2587.                 break ;        
  2588.             
  2589.             case iEditRendererPrefsItem:
  2590.                 {
  2591.                     /* this should probably be factored out somewhere */
  2592.                     TQ3RendererObject       qd3dRenderer;
  2593.                     TQ3ViewObject           qd3dView;   
  2594.                     TQ3Status               qd3dStatus;
  2595.                     TQ3Boolean              qd3dCanceled;
  2596.                     TQ3DialogAnchor         qd3dAnchor ;
  2597.                                         
  2598.                     /*
  2599.                      * get the reference to our viewer document data structure
  2600.                      * from the long reference constant for the window.  Cast
  2601.                      * it to the appropriate type.  If we can't get it (i.e. it's
  2602.                      * null we want to bail
  2603.                      */
  2604.                     if(theDocumentHdl != NULL  
  2605.                         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  2606.                         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL)
  2607.                     {
  2608.                         
  2609.                         /* get the reference to the viewer object from our data structure  */
  2610.                         theViewer = (**theViewerHdl).fViewer ;
  2611.                         if(theViewer == NULL) 
  2612.                             return ;
  2613.                         
  2614.                         /* Get the renderer */
  2615.                         qd3dView = Q3ViewerGetView(theViewer);
  2616.                         qd3dStatus = Q3View_GetRenderer(qd3dView, &qd3dRenderer);
  2617.  
  2618.                         /* Put up the configure dialog */
  2619.                         if (Q3Renderer_HasModalConfigure(qd3dRenderer))
  2620.                         {
  2621.                             /* this will be modal */
  2622.                             qd3dAnchor.clientEventHandler = NULL;
  2623.                             qd3dStatus = Q3Renderer_ModalConfigure(
  2624.                                                     qd3dRenderer,
  2625.                                                     qd3dAnchor,
  2626.                                                     &qd3dCanceled);
  2627.                         }
  2628.  
  2629.                         /* Clean up */
  2630.                         qd3dStatus = Q3Object_Dispose(qd3dRenderer);
  2631.                         /*
  2632.                          * assume that the renderer prefs changed something 
  2633.                          * so redraw the content region of the window 
  2634.                          */
  2635.                         GetPort( &savedPort ) ;
  2636.                         SetPort( theWindow ) ;
  2637.                         InvalRect( &theWindow->portRect ) ;
  2638.                         SetPort( savedPort ) ;
  2639.                     }
  2640.                 }
  2641.                 break;
  2642.         }
  2643.     }
  2644.  
  2645. }
  2646.  
  2647. /*------------------------------------------------------------ */
  2648.  
  2649. /*
  2650.  * utility function to get the viewer object 
  2651.  * associated with a particular viewer window
  2652.  */
  2653.  
  2654.  
  2655. TQ3ViewerObject    GetViewerFromViewerWindow( WindowPtr theWindow )
  2656. {
  2657.     OSErr                theError = paramErr ;
  2658.     short                theRef ;
  2659.     TQ3ViewerObject        theViewer = NULL ;
  2660.     FSSpec                theFSSpec ;
  2661.     DocumentHdl            theDocumentHdl ;
  2662.     
  2663.     if( theWindow != NULL )        /* sanity check  */
  2664.     {
  2665.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2666.         if(theDocumentHdl != NULL  
  2667.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  2668.         {
  2669.             /* get the viewer object from the document */
  2670.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  2671.             if( theViewerHdl != NULL )
  2672.             {
  2673.                 theViewer = (**theViewerHdl).fViewer ;
  2674.             }
  2675.         }
  2676.     }
  2677.     return theViewer ;
  2678. }
  2679.  
  2680. /*------------------------------------------------------------ */
  2681.  
  2682. /*
  2683.  * utility function to get the GWorld object 
  2684.  * associated with a particular pict window
  2685.  */
  2686.  
  2687.  
  2688. GWorldPtr GetGWorldFromPictWindow( WindowPtr  theWindow ) 
  2689. {
  2690.     DocumentHdl            theDocumentHdl ;
  2691.     PictDataHdl            thePictDataHdl ;
  2692.     GWorldPtr            theGWorld = NULL;
  2693.     OSErr                theErr ;
  2694.     
  2695.     if( theWindow != NULL )        /* sanity check  */
  2696.     {
  2697.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2698.         if(theDocumentHdl != NULL
  2699.             && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  2700.             && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  2701.         {
  2702.             theGWorld = (**thePictDataHdl).fGWorld;
  2703.         }
  2704.     }
  2705.     return theGWorld ;
  2706. }
  2707. /*------------------------------------------------------------ */
  2708.  
  2709. /*
  2710.  * utility function to get the renderer associated with a particular
  2711.  * type.  Does a linear search of the pRendererList array to 
  2712.  * retrieve the renderer object associated with the type passed in.
  2713.  * Will return NULL if the renderer type is not in the list.
  2714.  */
  2715. TQ3RendererObject    GetRendererByType(TQ3ObjectType theRendererType)
  2716. {
  2717.     TQ3RendererObject    myRenderer = NULL ;
  2718.     long                theIndex ;
  2719.     
  2720.     for( theIndex = 0; theIndex < pRendererCount; theIndex++ ) 
  2721.     {
  2722.         if( pRendererList[ theIndex ].fRendererType    == theRendererType )
  2723.             myRenderer = pRendererList[ theIndex ].fRendererObject ;
  2724.     }
  2725.     return myRenderer ;
  2726. }
  2727.  
  2728. /*------------------------------------------------------------ */
  2729.  
  2730. /*
  2731.  * utility function to set the renderer for a viewer
  2732.  */
  2733.  
  2734. TQ3Status    ViewerSetRenderer( TQ3ObjectType theRendererType, TQ3ViewerObject theViewer )
  2735. {
  2736.     TQ3RendererObject    myRenderer = NULL ;
  2737.     long                theIndex ;
  2738.     TQ3ViewObject         myView ;
  2739.     TQ3Status            myStatus = kQ3Failure;
  2740.     OSErr                theError ;
  2741.     
  2742.     
  2743.     myRenderer = GetRendererByType( theRendererType ) ;
  2744.         
  2745.     /*
  2746.      * set the renderer for the view
  2747.      */
  2748.     myView = Q3ViewerGetView( theViewer );
  2749.     if( myView != NULL && myRenderer != NULL )
  2750.     {
  2751.         /* set the renderer to the one recovered in the loop above  */
  2752.         myStatus = Q3View_SetRenderer(myView, myRenderer) ;
  2753.         
  2754.     }
  2755.     return myStatus ;
  2756.  
  2757. }
  2758. /*------------------------------------------------------------ */
  2759.  
  2760. /*
  2761.  * handle menu commands in the renderer menu
  2762.  */
  2763.  
  2764.  
  2765. void HandleInteractiveRendererMenu( short menuItem )
  2766. {
  2767.     WindowPtr            theWindow ;
  2768.     TQ3ObjectType        theRendererType ;
  2769.     TQ3ViewerObject        theViewer ;
  2770.     GrafPtr                savedPort ;
  2771.     
  2772.     theWindow = FrontWindow() ;
  2773.  
  2774.     if( theWindow != NULL )
  2775.     {
  2776.         theViewer = GetViewerFromViewerWindow( theWindow ) ;    
  2777.         theRendererType = pInteractiveTypes[ menuItem - 1 ] ;
  2778.         ViewerSetRenderer( theRendererType, theViewer ) ;
  2779.         GetPort(&savedPort) ;
  2780.         SetPort((GrafPtr)theWindow) ;
  2781.         InvalRect(&theWindow->portRect) ;
  2782.         SetPort(savedPort) ;
  2783.     }
  2784. }
  2785.  
  2786.  
  2787. /*------------------------------------------------------------ */
  2788.  
  2789. /*
  2790.  *  If any of the variable argument scrap types are available for pasting from
  2791.  *  the scrap, deliver the first one.  Otherwise, deliver 0.  For example,
  2792.  *    
  2793.  *      if (whichType = CanPaste(3,'TEXT','PICT','STUF')) ...
  2794.  *
  2795.  *  There can be any number of types in the list, as long as the preceding count, n,
  2796.  *  is correct.
  2797.  */
  2798.  
  2799. static OSType CanPaste(int n, ...)
  2800.     {
  2801.         register OSType nextType,ans = 0L;
  2802.         long err,offset;
  2803.         va_list nextArg;
  2804.         
  2805.         va_start(nextArg,n);
  2806.         nextType = va_arg(nextArg, OSType);
  2807.         
  2808.         while (n-- > 0) {
  2809.             err = GetScrap(NULL, nextType, &offset);
  2810.             if (err >= -1) {
  2811.                 ans = nextType;
  2812.                 break;
  2813.                 }
  2814.             nextType = va_arg(nextArg, OSType);
  2815.             }
  2816.         
  2817.         va_end(nextArg);
  2818.         return(ans);
  2819.     }
  2820.  
  2821.  
  2822. /*------------------------------------------------------------ */
  2823.  
  2824. /*
  2825.  *    Deliver the number of the current editText item in given dialog if any text
  2826.  *    is selected in it, or 0 if none selected.
  2827.  */
  2828.  
  2829. int TextSelected(DialogPtr dlog)
  2830. {
  2831.     register TEHandle        textH; 
  2832.     short                     item = 0;
  2833.     
  2834.     textH = ((DialogPeek)dlog)->textH;
  2835.     if (*textH)
  2836.         if ( (*textH)->selStart != (*textH)->selEnd )
  2837.             item = ((DialogPeek)dlog)->editField+1;
  2838.             
  2839.     return(item);
  2840. }
  2841.  
  2842.  
  2843.  
  2844.  
  2845. /*------------------------------------------------------------ */
  2846.  
  2847. /*
  2848.  * filter proc for the non-interactive renderer dialog
  2849.  */
  2850.  
  2851.  
  2852. pascal Boolean OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit)
  2853. {
  2854.  
  2855.     ModalFilterUPP         theProc ;
  2856.     Boolean                retVal ;
  2857.     
  2858.     static    Boolean        isDisabled = false ;
  2859.     OSErr                theErr = noErr ;
  2860.     
  2861.     /* stuff for getditems etc */
  2862.     Str255                theItem ;
  2863.     short                iKind;
  2864.     Handle                iHandle;
  2865.     Rect                iRect;
  2866.     char                theKey ;
  2867.     
  2868.     
  2869.     /* get the std filter proc */
  2870.     
  2871.     theErr = GetStdFilterProc( &theProc ) ;
  2872.     
  2873.     if( theErr != noErr )
  2874.         ExitToShell() ;
  2875.         
  2876.     /* try to call the standard filter, if it handles the event, we don't */
  2877.     if( !(retVal = CallModalFilterProc(theProc, dlg, event, itemHit)) )
  2878.     {
  2879.         switch (event->what) {
  2880.     
  2881.             case nullEvent:
  2882.                 break;
  2883.     
  2884.             case keyDown:
  2885.             case autoKey:
  2886.                   theKey = event->message & charCodeMask;
  2887.         
  2888.                 if( isalpha(theKey) || ispunct(theKey) || isspace(theKey) ) 
  2889.                 {
  2890.                     /* It's not a number, reject it */
  2891.                     SysBeep(1);
  2892.                     
  2893.                     /* tell the dialog manager that we handled this already and 
  2894.                      * it doesn't have to, so the keystroke will _not_ get 
  2895.                      * added to the edit line 
  2896.                      */
  2897.                     retVal = true; 
  2898.                 }
  2899.                 else if (event->modifiers & cmdKey) {
  2900.                     unsigned char     ch = (unsigned char)event->message;
  2901.                     
  2902.                     switch(ch) {
  2903.                     
  2904.                         case 'x':
  2905.                         case 'X':
  2906.                             if (TextSelected(dlg)) { 
  2907.                                 SystemEdit(3); 
  2908.                                 ZeroScrap(); 
  2909.                                 DlgCut(dlg); 
  2910.                                 TEToScrap(); 
  2911.                             }
  2912.                             break;
  2913.                             
  2914.                         case 'c':
  2915.                         case 'C':
  2916.                             if (TextSelected(dlg)) { 
  2917.                                 SystemEdit(3); 
  2918.                                 ZeroScrap(); 
  2919.                                 DlgCopy(dlg); 
  2920.                                 TEToScrap(); 
  2921.                             }
  2922.                             break;
  2923.                             
  2924.                         case 'v':
  2925.                         case 'V':
  2926.                             if (CanPaste(1,'TEXT')) { 
  2927.                                 TEFromScrap(); 
  2928.                                 DlgPaste(dlg); 
  2929.                             }
  2930.                             break ;
  2931.                             
  2932.                         case 'a':
  2933.                         case 'A':
  2934.                             if (((DialogPeek)dlg)->editField >= 0) {
  2935.                                 /* Dialog has text edit item: select all */
  2936.                                 SelIText(dlg,((DialogPeek)dlg)->editField+1,0,32767);
  2937.                             }
  2938.                             *itemHit = 0;
  2939.                             break;
  2940.                             
  2941.                     }                
  2942.                 }
  2943.                 else
  2944.                     retVal = false;
  2945.                     
  2946.                 break ;
  2947.     
  2948.             case updateEvt:
  2949.                 PenPat( &qd.ltGray ) ;
  2950.                 
  2951.                 /* get the text item we are drawing in */
  2952.                 GetDialogItem ( dlg, kFinalRendrSep1, &iKind, &iHandle, &iRect) ;
  2953.                 FrameRect(&iRect ) ;
  2954.                 GetDialogItem ( dlg, kFinalRendrSep2, &iKind, &iHandle, &iRect) ;
  2955.                 FrameRect(&iRect ) ;
  2956.                 GetDialogItem ( dlg, kFinalRendrSep3, &iKind, &iHandle, &iRect) ;
  2957.                 FrameRect(&iRect ) ;
  2958.                 PenPat( &qd.black ) ;        
  2959.                 /*
  2960.                  * enable or disable the OK button depending on whether 
  2961.                  * we made a selection yet
  2962.                  */
  2963.                 GetDialogItem(  dlg, ok, &iKind, &iHandle, &iRect) ;
  2964.                 
  2965.                 retVal = false;
  2966.                 break ;
  2967.     
  2968.             default:
  2969.                 retVal = false;
  2970.                 break ;
  2971.         }
  2972.     }
  2973.     
  2974.     return retVal ;
  2975. }
  2976.  
  2977. /*------------------------------------------------------------ */
  2978.  
  2979. /*
  2980.  * IdleProgress method, handles setup, drawing and teardown for
  2981.  * the renderer progress dialog 
  2982.  */
  2983.  
  2984. TQ3Status MyViewIdleProgressMethod(
  2985.     TQ3ViewObject        view,
  2986.     const void            *idlerData,        /* contains the dialog ref */
  2987.     unsigned long        current,
  2988.     unsigned long        completed)
  2989. {
  2990.  
  2991.     /* 
  2992.      * Return kQ3Failure to cancel rendering, kQ3Success to continue. Don't
  2993.       * bother posting an error.
  2994.       */
  2995.       
  2996.     TQ3Status                    retVal = kQ3Success ;
  2997.     DialogPtr                    theDialog = (DialogPtr)idlerData ;
  2998.     ProgressBarDlogInfoHdl        theInfo ;
  2999.     CGrafPtr                    savedPort ;
  3000.     GDHandle                    savedGDH ;
  3001.     EventRecord                    theEvent ;
  3002.     char                        theKey ;
  3003.     
  3004.     /*
  3005.      *    Q3View_SetIdleMethod registers a callback that can be called
  3006.      *    by the system during rendering.  Unfortunately there is no way yet
  3007.      *    to set timer intervals when you want to be called.  Basically, it is
  3008.      *    up to the application's idler callback to check clocks to see if you
  3009.      *    were called back only a millisecond ago or an hour ago!
  3010.      *
  3011.      *    Q3View_SetIdleProgressMethod registers a callback that also gives
  3012.      *    progress information. This information is supplied by the renderer, and
  3013.      *    may or may not be based on real time.
  3014.      *
  3015.      *    If a renderer doesn't support the progress method, your method will be
  3016.      *    called with current == 0 and completed == 0.
  3017.      *    
  3018.      *    Otherwise, you are GUARANTEED to get called at least 2 or more times:
  3019.      *    
  3020.      *    ONCE            idleMethod(view, 0, n)        -> Initialize, Show Dialog
  3021.      *    zero or more    idleMethod(view, 1..n-1, n) -> Update progress
  3022.      *    ONCE            idleMethod(view, n, n)        -> Exit, Hide Dialog
  3023.      *    
  3024.      *    "current" is guaranteed to be less than or equal to "completed"
  3025.      *    "completed" may change values, but current/complete always indicates
  3026.      *    the degree of completion.
  3027.      *
  3028.      *    The calling conventions aid in managing any data associated with a 
  3029.      *    progress user interface indicator.
  3030.      */
  3031.     if( current == 0 && completed == 0 )
  3032.     {
  3033.         /* renderer doesn't support progress info, so just return success */
  3034.         retVal = kQ3Success ;
  3035.     }
  3036.     else
  3037.     {
  3038.         if( current == 0 )
  3039.         {
  3040.             /*
  3041.              * make a new progress bar dlog struct - we wait til here because 
  3042.              * prior to this point we have no idea what the max and min values
  3043.              * are for the dialog.
  3044.              */
  3045.             theInfo = PB_New( theDialog, kProgressBarPBItemID, completed, current ) ;
  3046.             
  3047.             /* the theInfo rec in the refCon field of the dialog */
  3048.             SetWRefCon((WindowPtr)theDialog, (long)theInfo);
  3049.             
  3050.             GetGWorld( &savedPort, &savedGDH ) ;
  3051.             SetGWorld( (CGrafPtr)theDialog, NULL ) ;
  3052.             
  3053.             /* make the hidden dialog visible */
  3054.             ShowWindow( theDialog ) ; 
  3055.             
  3056.             /* select it */
  3057.             SelectWindow( theDialog ) ;
  3058.             
  3059.             /* draw the dialog */
  3060.             UpdateDialog( theDialog, theDialog->visRgn ) ;
  3061.             
  3062.             SetGWorld( savedPort, savedGDH ) ;
  3063.             
  3064.         }
  3065.         else if( current == completed )
  3066.         {            
  3067.             GetGWorld( &savedPort, &savedGDH ) ;
  3068.             SetGWorld( (CGrafPtr)theDialog, NULL ) ;
  3069.             
  3070.             /* draw the last part of the progress bar */
  3071.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3072.             (**theInfo).thePBCurrValue = current ;
  3073.             
  3074.             /* update the progress bar */
  3075.             PB_Update( theInfo ) ;
  3076.             
  3077.             SetGWorld( savedPort, savedGDH ) ;
  3078.  
  3079.             /* tear down the progressbar dialog struct */
  3080.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3081.             DisposeHandle( (Handle)theInfo ) ;
  3082.             HideWindow( theDialog ) ;
  3083.         }
  3084.         else
  3085.         {            
  3086.             /* update the progress bar */
  3087.             GetGWorld( &savedPort, &savedGDH ) ;
  3088.             SetGWorld( (CGrafPtr)theDialog, NULL ) ;
  3089.  
  3090.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3091.             (**theInfo).thePBCurrValue = current ;
  3092.             
  3093.             /* update the progress bar */
  3094.             InvalRect( &theDialog->portRect ) ;
  3095.             DrawDialog( theDialog ) ;
  3096.             PB_Update( theInfo ) ;
  3097.             
  3098.             SetGWorld( savedPort, savedGDH ) ;
  3099.             
  3100.         }
  3101.     }
  3102.     
  3103.     /* 
  3104.      * last thing... check the event queue to see if there is a keydown event,
  3105.      * we want to see if the user hit command period to cancel.  Be warned - this 
  3106.      * way of doing this will flush keyevents from the event queue.
  3107.      */
  3108.      
  3109.     if( GetOSEvent( (keyDownMask | autoKeyMask), &theEvent) == true )
  3110.     {
  3111.         /* examine the event to see if its a command period */
  3112.         theKey = theEvent.message & charCodeMask;
  3113.         if( (theEvent.modifiers & cmdKey) && theKey == '.')
  3114.         {
  3115.             /* 
  3116.              * we want to cancel, we can signal this by returning kQ3Failure
  3117.              * before leaving this function, clean up & hide the progress dialog
  3118.              */
  3119.              
  3120.             /* tear down the progressbar dialog struct */
  3121.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3122.             DisposeHandle( (Handle)theInfo ) ;
  3123.             HideWindow( theDialog ) ;
  3124.  
  3125.             SysBeep(10) ;
  3126.             retVal = kQ3Failure ;
  3127.         }
  3128.         
  3129.     }
  3130.     return retVal ;
  3131. }
  3132.  
  3133.  
  3134. /*------------------------------------------------------------ */
  3135.  
  3136. /*
  3137.  * The user chose to render with a non interactive renderer, put
  3138.  * up a dialog to allow them to select and configure the renderer
  3139.  * and copy the appropriate values from the current viewer window.
  3140.  * 
  3141.  * this seems like a long winded way to do this.  We create a viewer
  3142.  * use that to image (which will take advantage of the renderers updates
  3143.  * get the pict for the viewer, image that into the offscreen for the window.
  3144.  */
  3145.  
  3146.  
  3147. void HandleViewFinalRendererOption( void ) 
  3148. {
  3149.     WindowPtr            theFrontWindow ;
  3150.     short                itemHit ;
  3151.     GrafPtr                savedPort ;
  3152.     popupPrivateData    **myPopupPrivateDataPtr ;
  3153.     
  3154.     short                iKind;
  3155.     Handle                iHandle;
  3156.     Rect                iRect;
  3157.     
  3158.     MenuHandle            thePopupMenuHdl ;
  3159.     unsigned char        rendererName[255] ;
  3160.     TQ3RendererObject    theRenderer ;
  3161.     unsigned char        numText[255] ;
  3162.     
  3163.     OSErr                 theErr ;
  3164.     
  3165.     long                width ;
  3166.     long                height ;
  3167.     long                theControlValue = 0;
  3168.  
  3169.     /* 
  3170.      * the final renderer option should only be available for a 
  3171.      * viewer window, so we can assume the the front window at the 
  3172.      * time this is called is a viewer
  3173.      */
  3174.     theFrontWindow = FrontWindow() ;
  3175.  
  3176.     GetPort( &savedPort ) ;
  3177.     SetPort( (GrafPtr)gFinalRenderDialog ) ;
  3178.     
  3179.     /* 
  3180.      * TODO set the window size to whatever the current viewer window size is.
  3181.      * Since this can only get called is the front window is a viewer window,
  3182.      * indeed the exact window we are concerned with, then just use the dimensions
  3183.      * of the viewer.
  3184.      */
  3185.     width  = theFrontWindow->portRect.right - theFrontWindow->portRect.left ;
  3186.     height = theFrontWindow->portRect.bottom - theFrontWindow->portRect.top ;
  3187.     
  3188.     NumToString ( height, numText ) ;
  3189.     GetDialogItem ( gFinalRenderDialog, kFinalRendrHeight, &iKind, &iHandle, &iRect) ;
  3190.     SetDialogItemText ( iHandle, numText ) ;
  3191.     
  3192.     NumToString ( width, numText ) ;
  3193.     GetDialogItem ( gFinalRenderDialog, kFinalRendrWidth, &iKind, &iHandle, &iRect) ;
  3194.     SetDialogItemText ( iHandle, numText ) ;
  3195.     
  3196.     InvalRect( &((GrafPtr)gFinalRenderDialog)->portRect) ;
  3197.  
  3198.     SetDialogDefaultItem(gFinalRenderDialog, kStdOkItemIndex) ;
  3199.  
  3200.     ShowWindow( (WindowPtr)gFinalRenderDialog ) ;
  3201.     SelectWindow( (WindowPtr)gFinalRenderDialog ) ;
  3202.     
  3203.     do {
  3204.         ModalDialog( gModalFilterProcUPP, &itemHit ) ;
  3205.         
  3206.         if( itemHit == kFinalRendrPopup ) {
  3207.         
  3208.             /* the user choose the popup.  The item number selected will be the control value
  3209.              * we need to get the menuhandle associated with the control, it is in the private
  3210.              * control data field, as documented in Inside Macintosh: Toolbox page 5-77
  3211.              */
  3212.             
  3213.             /* get the control handle for the popup    */        
  3214.             GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  3215.             
  3216.             /* extract from the control the menuhandle */
  3217.             myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  3218.             thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ;
  3219.     
  3220.             /* get the string associated with the users selection */
  3221.             HLock((Handle)iHandle) ;
  3222.             theControlValue = GetControlValue((ControlHandle)iHandle) ;
  3223.  
  3224.             GetMenuItemText ( thePopupMenuHdl, theControlValue, rendererName );
  3225.             HUnlock((Handle)iHandle) ;
  3226.                         
  3227.             /* reset itemHit to something else */
  3228.             itemHit = 0 ;
  3229.         
  3230.         }
  3231.         else if( itemHit == kFinalRendrConfigure ) {
  3232.             
  3233.             /* get the control handle for the popup    */        
  3234.             GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  3235.             
  3236.             /* extract from the control the menuhandle */
  3237.             myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  3238.             thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ;
  3239.     
  3240.             /* get the string associated with the users selection */
  3241.             HLock((Handle)iHandle) ;
  3242.             theControlValue = GetControlValue((ControlHandle)iHandle) ;
  3243.                         
  3244.             if( theControlValue != 0 )
  3245.             {
  3246.                 theRenderer = GetRendererByType( pNonInteractiveTypes[theControlValue-1] ) ;
  3247.                 
  3248.                 if( theRenderer != NULL && Q3Renderer_HasModalConfigure( theRenderer )) 
  3249.                 {
  3250.                     TQ3DialogAnchor         qd3dAnchor ;
  3251.                     TQ3Boolean                qd3dCanceled ;
  3252.                     TQ3Status                theStatus ;
  3253.                     
  3254.                     
  3255.                     /* the renderer prefs dialog will be modal */
  3256.                     qd3dAnchor.clientEventHandler = NULL ;
  3257.                     theStatus = Q3Renderer_ModalConfigure(
  3258.                                             theRenderer,
  3259.                                             qd3dAnchor,
  3260.                                             &qd3dCanceled) ;
  3261.                                             
  3262.                 }
  3263.             }
  3264.             else
  3265.                 SysBeep(10) ;
  3266.         }
  3267.     } while( itemHit != kStdCancelItemIndex && itemHit != kStdOkItemIndex ) ;
  3268.     
  3269.     /* we're done with the dialog window, hide it 'till next time */
  3270.     HideWindow( (WindowPtr)gFinalRenderDialog ) ;
  3271.     
  3272.     /* check we didn't cancel */
  3273.     if( itemHit == kStdOkItemIndex )
  3274.     {
  3275.         TQ3ViewerObject        tempViewer ;
  3276.         WindowPtr            finalImageWin ;
  3277.         PicHandle            theImage ;
  3278.  
  3279.         /* get the control handle for the popup    */        
  3280.         GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  3281.         
  3282.         /* extract from the control the menuhandle */
  3283.         myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  3284.         thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ;
  3285.  
  3286.         /* get the string associated with the users selection */
  3287.         HLock((Handle)iHandle) ;
  3288.         theControlValue = GetControlValue((ControlHandle)iHandle) ;
  3289.  
  3290.         GetMenuItemText ( thePopupMenuHdl, theControlValue, rendererName );
  3291.         HUnlock((Handle)iHandle) ;
  3292.                     
  3293.         /* reset itemHit to something else */
  3294.         itemHit = 0 ;
  3295.         
  3296.         /* get the window size - we can get the dialog item string and just StringToNum it
  3297.          * since our filter proc filders out all key stroked except digits
  3298.          */
  3299.         GetDialogItem ( gFinalRenderDialog, kFinalRendrHeight, &iKind, &iHandle, &iRect) ;
  3300.         GetDialogItemText ( iHandle, numText ) ;
  3301.         StringToNum ( numText, &height ) ;
  3302.         
  3303.         GetDialogItem ( gFinalRenderDialog, kFinalRendrWidth, &iKind, &iHandle, &iRect) ;
  3304.         GetDialogItemText ( iHandle, numText ) ;
  3305.         StringToNum ( numText, &width ) ;
  3306.                 
  3307.         /* make a new window with the renderer name of the correct size */
  3308.         finalImageWin = DoCreateNewPictWindow( rendererName, width, height ) ;
  3309.         
  3310.         /* make a viewer for this window with no controller */
  3311.         if( finalImageWin != NULL ) 
  3312.         {
  3313.             /* get these from the original viewer referenced by FrontWindow */
  3314.             TQ3GroupObject        savedGroup ;
  3315.             TQ3CameraObject        savedCamera ;
  3316.             TQ3GroupObject        savedLights ;
  3317.             TQ3ColorARGB        savedBGColor ;
  3318.             
  3319.             TQ3ViewerObject        originalViewer ;
  3320.             TQ3ViewObject        originalView ;
  3321.             unsigned long        theViewerFlags ;
  3322.             GWorldPtr            theGWorld ; 
  3323.             
  3324.             CGrafPtr            savedPort ;
  3325.             GDHandle            savedGDH ;
  3326.  
  3327.             theGWorld = GetGWorldFromPictWindow( finalImageWin ) ;
  3328.             
  3329.             /* make a temp viewer to use to make the PICT */
  3330.             if( theGWorld != NULL 
  3331.                 && (tempViewer = Q3ViewerNew( (CGrafPtr)theGWorld, 
  3332.                                 &theGWorld->portRect, 
  3333.                                 kQ3ViewerDefault )) != NULL)
  3334.             {
  3335.                 
  3336.                 /* lock the viewer's GWorld for updates */
  3337.                 LockPixels(GetGWorldPixMap(theGWorld)) ;
  3338.  
  3339.                 GetGWorld( &savedPort, &savedGDH ) ;
  3340.                 SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  3341.  
  3342.                 originalViewer = GetViewerFromViewerWindow( theFrontWindow ) ;
  3343.  
  3344.                 if( originalViewer != NULL ) 
  3345.                 {
  3346.                     TQ3ViewObject        newView ;
  3347.                     
  3348.                     /* set the group up, copy from original viewer */
  3349.                     savedGroup = Q3ViewerGetGroup( originalViewer ) ;
  3350.                     if( savedGroup != NULL )
  3351.                     {
  3352.                         Q3ViewerUseGroup( tempViewer, savedGroup) ;
  3353.                         Q3Object_Dispose( savedGroup ) ;
  3354.                     }
  3355.                     
  3356.                     /* copy the camera from the original viewer */
  3357.                     originalView = Q3ViewerGetView( originalViewer ) ;
  3358.                     newView = Q3ViewerGetView( tempViewer ) ;
  3359.                     
  3360.                     if( originalView != NULL )
  3361.                     {
  3362.                         Q3View_GetCamera( originalView, &savedCamera );
  3363.                         if( savedCamera != NULL )
  3364.                         {
  3365.                             Q3View_SetCamera( newView, savedCamera );
  3366.                             Q3Object_Dispose( savedCamera ) ;
  3367.                         }
  3368.                     }
  3369.                     
  3370.                     /* copy the light group from the original viewer */
  3371.                     if( originalView != NULL )
  3372.                     {
  3373.                         Q3View_GetLightGroup( originalView, &savedLights );
  3374.                         if( savedCamera != NULL )
  3375.                         {
  3376.                             Q3View_SetLightGroup( newView, savedLights );
  3377.                             Q3Object_Dispose( savedLights ) ;
  3378.                         }
  3379.                     }
  3380.  
  3381.                     /* copy the background color from the original viewer */
  3382.                     if( originalView != NULL )
  3383.                     {
  3384.                         Q3ViewerGetBackgroundColor( originalViewer, &savedBGColor ) ;
  3385.                         if( savedCamera != NULL )
  3386.                         {
  3387.                             Q3ViewerSetBackgroundColor( tempViewer, &savedBGColor ) ;
  3388.                         }
  3389.                     }
  3390.                     
  3391.                     /*
  3392.                      * we don't need to dispose the view, since viewergetview doesn't
  3393.                      * increment the reference counts of the viewer.
  3394.                      */
  3395.                     
  3396.                     theViewerFlags = Q3ViewerGetFlags( tempViewer ) ;
  3397.                     
  3398.                     theViewerFlags = theViewerFlags &~ kQ3ViewerControllerVisible;
  3399.                     theViewerFlags = theViewerFlags &~ kQ3ViewerDrawFrame;
  3400.                     theViewerFlags = theViewerFlags &~ kQ3ViewerDrawDragBorder;
  3401.                     
  3402.                     Q3ViewerSetFlags( tempViewer, theViewerFlags ) ;
  3403.                     
  3404.                     /* this is a little funky - we are using a modeless dialog to display the
  3405.                      * progress of the render, but the main event loop will never get called,
  3406.                      * since the dialog is only "called back" from the render.
  3407.                      */
  3408.                                      
  3409.                     if( gProgressModelessDialog != NULL )
  3410.                     {
  3411.                         /* install the callback */
  3412.                         Q3View_SetIdleProgressMethod( 
  3413.                                 newView, 
  3414.                                 MyViewIdleProgressMethod,
  3415.                                 (const void *)gProgressModelessDialog ) ;
  3416.                     
  3417.                     }
  3418.                     
  3419.                     /* image the document */
  3420.  
  3421.                     /* set the renderer to the renderer from the popup for this document */
  3422.                     ViewerSetRenderer( pNonInteractiveTypes[theControlValue-1], tempViewer ) ;
  3423.                     Q3ViewerDraw( tempViewer ) ;
  3424.                     
  3425.                     /* dispose of the viewer object */
  3426.                     Q3ViewerDispose( tempViewer ) ;
  3427.                     
  3428.                     /*
  3429.                      * it is possible that if the renderer does not follow the calling conventions
  3430.                      * to update the progress dialog, that that dialog can be lest on the screen
  3431.                      * so check the fron window, if it is the progress dialog then hide it
  3432.                      */
  3433.                     if( FrontWindow() == gProgressModelessDialog )
  3434.                         HideWindow( gProgressModelessDialog ) ;
  3435.                 }
  3436.                 
  3437.                 SetGWorld( savedPort, savedGDH ) ;
  3438.                 
  3439.                 /* lock the viewer's GWorld for updates */
  3440.                 UnlockPixels(GetGWorldPixMap(theGWorld)) ;
  3441.  
  3442.             }
  3443.         }
  3444.     }
  3445.     else
  3446.     {
  3447.         SelectWindow( theFrontWindow ) ;
  3448.         SetPort( savedPort ) ;
  3449.     }    
  3450. }
  3451.  
  3452. /*------------------------------------------------------------ */
  3453.  
  3454. /*
  3455.  * handle menu commands in the view menu
  3456.  */
  3457.  
  3458.  
  3459. void HandleViewMenu( short menuItem )
  3460. {
  3461.     DocumentHdl            theDocumentHdl ;
  3462.     ViewerDataHdl        theViewerHdl ;
  3463.     WindowPtr            theWindow ;
  3464.     TQ3ViewerObject        theViewer ;
  3465.  
  3466.     unsigned long        theViewerFlags;
  3467.     Rect                theTmpRect ;
  3468.     GrafPtr                savedPort ;
  3469.     RGBColor            theRGBColor ;
  3470.     TQ3ColorARGB        theViewerBGColor;
  3471.  
  3472.     theWindow = FrontWindow() ;
  3473.     
  3474.     if( theWindow != NULL )
  3475.     {
  3476.         /*
  3477.          * get the reference to our viewer document data structure
  3478.          * from the long reference constant for the window.  Cast
  3479.          * it to the appropriate type.  If we can't get it (i.e. it's
  3480.          * null we want to bail
  3481.          */
  3482.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3483.         if(theDocumentHdl == NULL) 
  3484.             return ;
  3485.         
  3486.         /* get the reference to the viewer object from our data structure  */    
  3487.         if((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) == NULL)
  3488.             return ;
  3489.             
  3490.         /* get the reference to the viewer object from our data structure  */    
  3491.         theViewer = (**theViewerHdl).fViewer ;
  3492.         if(theViewer == NULL) 
  3493.             return ;
  3494.         
  3495.         /*
  3496.          * since most of the items in this menu rely on adjusting
  3497.          * the viewer flags, we'll get the flags here so we can
  3498.          * bitwise manipulate them in the switch below
  3499.          */ 
  3500.         theViewerFlags = Q3ViewerGetFlags( theViewer ) ;
  3501.     
  3502.         switch ( menuItem ) 
  3503.         {
  3504.             case iViewFinalRendererItem:
  3505.             
  3506.                 HandleViewFinalRendererOption() ;
  3507.                 break ;
  3508.  
  3509.             /*
  3510.              * the renderer item in this menu is handled
  3511.              * by handlers for it's respective hierarchical        
  3512.              * menus, so we just need to handle the ones below
  3513.              */    
  3514.             
  3515.             case iViewBadgeItem:
  3516.                 /* 
  3517.                  * this toggles the viewer bage and hides the
  3518.                  * vcontroller, clicking in the badge will
  3519.                  * hide the badge and show the controller
  3520.                  */
  3521.                 theViewerFlags ^= kQ3ViewerShowBadge;
  3522.                 theViewerFlags ^= kQ3ViewerControllerVisible;
  3523.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3524.                 break ;
  3525.                 
  3526.             case iViewCameraButtonItem:
  3527.                 theViewerFlags ^= kQ3ViewerButtonCamera ;
  3528.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3529.                 break ;
  3530.                 
  3531.             case iViewTruckButtonItem:
  3532.                 theViewerFlags ^= kQ3ViewerButtonTruck ;
  3533.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3534.                 break ;
  3535.                 
  3536.             case iViewOrbitButtonItem:
  3537.                 theViewerFlags ^= kQ3ViewerButtonOrbit ;
  3538.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3539.                 break ;
  3540.                 
  3541.             case iViewZoomButtonItem:
  3542.                 theViewerFlags ^= kQ3ViewerButtonZoom ;
  3543.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3544.                 break ;
  3545.                 
  3546.             case iViewDollyButtonItem:
  3547.                 theViewerFlags ^= kQ3ViewerButtonDolly ;
  3548.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3549.                 break ;
  3550.                 
  3551.             case iViewInsetNFrameItem:
  3552.                 /*
  3553.                  * this toggles drawing the viewer slightly smaller 
  3554.                  *than the window.  We key off the kQ3ViewerDrawFrame
  3555.                  * viewer flag - if it is set then we are already inset
  3556.                  */
  3557.                 theTmpRect = theWindow->portRect ;
  3558.                 if( theViewerFlags & kQ3ViewerDrawFrame ) 
  3559.                 {
  3560.                     Q3ViewerSetBounds( theViewer, &theTmpRect ) ;
  3561.                 }
  3562.                 else
  3563.                 {
  3564.                     InsetRect( &theTmpRect, kInsetPixelsConst, kInsetPixelsConst ) ;
  3565.                     Q3ViewerSetBounds( theViewer, &theTmpRect ) ;
  3566.                 }
  3567.                 theViewerFlags ^= kQ3ViewerDrawFrame ;
  3568.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3569.                 
  3570.                 GetPort( &savedPort ) ;
  3571.                 SetPort( (GrafPtr)theWindow ) ;
  3572.                 EraseRect( &theWindow->portRect ) ;
  3573.                 SetPort( savedPort ) ;
  3574.                 
  3575.                 break ;
  3576.             
  3577.             case iViewSetBackgroundColorItem:
  3578.     
  3579.                 Q3ViewerGetBackgroundColor(theViewer, &theViewerBGColor);
  3580.                 theRGBColor.red = theViewerBGColor.r * 65535.0;
  3581.                 theRGBColor.green = theViewerBGColor.g * 65535.0;
  3582.                 theRGBColor.blue = theViewerBGColor.b * 65535.0;
  3583.                 
  3584.                 if(BackgroundColor( &theRGBColor, "\pPick a viewer background color:" ))
  3585.                 {
  3586.                     theViewerBGColor.a = 1;
  3587.                     theViewerBGColor.r = theRGBColor.red / 65535.0;
  3588.                     theViewerBGColor.g = theRGBColor.green / 65535.0;
  3589.                     theViewerBGColor.b = theRGBColor.blue / 65535.0;
  3590.                     Q3ViewerSetBackgroundColor(theViewer, &theViewerBGColor);
  3591.                 }
  3592.                 break;                                
  3593.         }
  3594.     }
  3595.     
  3596.     GetPort( &savedPort ) ;
  3597.     SetPort( (GrafPtr)theWindow ) ;
  3598.     InvalRect( &theWindow->portRect ) ;
  3599.     SetPort( savedPort ) ;
  3600. }
  3601.  
  3602. Boolean BackgroundColor(RGBColor *theRGBColor, unsigned char *thePrompt )
  3603. {
  3604.     ColorPickerInfo        cpInfo;
  3605.     Boolean                returnValue = false ;
  3606.     
  3607.     /* setting input color to be an RGB color  */
  3608.     cpInfo.theColor.color.rgb.red = (*theRGBColor).red;
  3609.     cpInfo.theColor.color.rgb.blue = (*theRGBColor).blue;
  3610.     cpInfo.theColor.color.rgb.green = (*theRGBColor).green;
  3611.     
  3612.     cpInfo.theColor.profile = 0L;
  3613.     
  3614.     /* no colorsync destination profile  */
  3615.     cpInfo.dstProfile = 0L;
  3616.     
  3617.     /* set the color picker flags  */
  3618.     cpInfo.flags = AppIsColorSyncAware | CanModifyPalette | 
  3619.                         CanAnimatePalette;
  3620.                         
  3621.     /* center dialog box on the deepest color screen  */
  3622.     cpInfo.placeWhere = kDeepestColorScreen;
  3623.     
  3624.     /* use the system default picker  */
  3625.     cpInfo.pickerType = 0L;
  3626.     
  3627.     /* install event filter and color-changed functions  */
  3628.     cpInfo.eventProc = NULL;            
  3629.     cpInfo.colorProc = NULL;
  3630.     cpInfo.colorProcData = 0L;
  3631.     
  3632.     /* sanity check  */
  3633.     if( thePrompt[ 0 ] >= 255 )
  3634.         thePrompt[ 0 ] = 255 ;
  3635.         
  3636.     BlockMove( thePrompt, cpInfo.prompt, thePrompt[0] ) ;
  3637.     
  3638.     /* describe the Edit menu for Color Picker Manager  */
  3639.     cpInfo.mInfo.editMenuID = mEditMenu ;
  3640.     cpInfo.mInfo.cutItem     = iEditCutItem;
  3641.     cpInfo.mInfo.copyItem     = iEditCopyItem;
  3642.     cpInfo.mInfo.pasteItem    = iEditPasteItem;
  3643.     cpInfo.mInfo.clearItem     = iEditClearItem;
  3644.     cpInfo.mInfo.undoItem     = iEditUndoItem;
  3645.  
  3646.     /* display dialog box to allow user to choose a color  */
  3647.     if(PickColor(&cpInfo) == noErr && cpInfo.newColorChosen)
  3648.     {
  3649.         /* use this new color  */
  3650.         (*theRGBColor).red = cpInfo.theColor.color.rgb.red ;
  3651.         (*theRGBColor).blue = cpInfo.theColor.color.rgb.blue ;
  3652.         (*theRGBColor).green = cpInfo.theColor.color.rgb.green ;
  3653.         
  3654.         /* set up the return value  */
  3655.         returnValue = cpInfo.newColorChosen ;
  3656.     }
  3657.         
  3658.     return returnValue ;
  3659. }
  3660.  
  3661. /*------------------------------------------------------------ */
  3662.  
  3663. /*
  3664.  * make sure that menus are enabled and disabled in an
  3665.  * appropriate manner
  3666.  */
  3667.  
  3668.  
  3669. void AdjustMenus( void ) 
  3670. {
  3671.     MenuHandle            theMenu ;
  3672.     DocumentHdl            theDocumentHdl ;
  3673.     WindowPtr            theWindow ;
  3674.     TQ3ViewerObject        theViewer ;
  3675.     TQ3ViewObject         myView ;
  3676.     TQ3Status            myStatus ;
  3677.     TQ3RendererObject    myRenderer ;
  3678.     TQ3ObjectType        theRendererType ;
  3679.     long                tmpLong, theScrapOffset ;
  3680.     unsigned long        theViewerFlags;
  3681.     unsigned long        theViewerState ;
  3682.     AdjustMenusProc        myAdjustMenus ;
  3683.     char                itemString[255] ;
  3684.     unsigned long        itemStringLength ;
  3685.  
  3686.     theWindow = FrontWindow() ;
  3687.     
  3688.     /* do we have a viewer window open  */
  3689.     if( theWindow != NULL ) {
  3690.         /*
  3691.          * get the reference to our viewer document data structure
  3692.          * from the long reference constant for the window.  Cast
  3693.          * it to the appropriate type.  If we can't get it (i.e. it's
  3694.          * null we want to bail
  3695.          */
  3696.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3697.         if(theDocumentHdl == NULL) 
  3698.             return ;
  3699.             
  3700.         myAdjustMenus = (**theDocumentHdl).procs->adjustMenusP ;
  3701.         
  3702.         if( myAdjustMenus != NULL )
  3703.             (*myAdjustMenus)(theWindow) ;
  3704.     }
  3705.     else {
  3706.     
  3707.         /* there is NOT a front window, set defaults for menu commands */
  3708.     
  3709.         /* adjust the file menu */
  3710.         theMenu = GetMHandle ( mFileMenu ) ;
  3711.         
  3712.         EnableItem ( theMenu, iFileNewItem );        /* always enabled */
  3713.         EnableItem ( theMenu, iFileOpenItem );        /* always enabled */
  3714.         EnableItem ( theMenu, iFileQuitItem );        /* always enabled */
  3715.  
  3716.         DisableItem ( theMenu, iFileCloseItem );
  3717.         DisableItem ( theMenu, iFileSaveItem );
  3718.         DisableItem ( theMenu, iFileSaveAsItem );
  3719.         DisableItem ( theMenu, iFileRevertItem );
  3720.         DisableItem ( theMenu, iFilePageSetupItem );
  3721.         DisableItem ( theMenu, iFilePrintItem );
  3722.  
  3723.         /* adjust the edit menu */
  3724.         theMenu = GetMHandle ( mEditMenu ) ;
  3725.         DisableItem ( theMenu, 0L );
  3726.         
  3727.         /* disable the entire view menu if there is no window */
  3728.         theMenu = GetMHandle ( mViewMenu ) ;
  3729.         DisableItem ( theMenu, 0L );
  3730.  
  3731.     }
  3732.     DrawMenuBar() ;
  3733. }
  3734.  
  3735. /*------------------------------------------------------------  */
  3736.  
  3737. /* Determining the 3D Viewer version 
  3738.  *
  3739.  * Version 1.5 of the 3D viewer adds some new APIs and new features. 
  3740.  * In order for an application to determine at runtime that the version 
  3741.  * 1.5 functionality of the 3D viewer is available an application must 
  3742.  * check the version of the viewer. Unfortunately prior to version 1.5 
  3743.  * the 3D viewer did not have a gestalt or an API call to get its version. 
  3744.  * Version 1.5 of the viewer adds a call Q3ViewerGetVersion. But an 
  3745.  * application will want to first check that the Q3ViewerGetVersion 
  3746.  * symbol is resolved before calling the Q3ViewerGetVersion function 
  3747.  * on the chance the user has an older version of viewer shared library 
  3748.  * installed. An application which depends on the newer functionality 
  3749.  * will then need to take appropriate action such as displaying an alert 
  3750.  * or disabling specific features.
  3751.  */
  3752.  
  3753. OSErr GetViewerVersion( unsigned long *major, unsigned long *minor ) 
  3754.     
  3755.     /*
  3756.      * version 1.0 of the QuickDraw 3D viewer did not 
  3757.      * have a get version call, so check to see if the 
  3758.      * symbol for the API routine descriptor is loaded
  3759.      */ 
  3760.     if((Boolean)Q3ViewerGetVersion == kUnresolvedCFragSymbolAddress) 
  3761.     {
  3762.         *major = 1; 
  3763.         *minor = 0; 
  3764.         return noErr; 
  3765.     } 
  3766.     else 
  3767.     { 
  3768.         return Q3ViewerGetVersion(major, minor); 
  3769.     } 
  3770. }
  3771.  
  3772.  
  3773. /*------------------------------------------------------------  */
  3774.  
  3775. /*
  3776.  *     DoDrawGrowIcon 
  3777.  *  
  3778.  *     Draw the grow icon. We do this in such a way that the scrollbar lines are 
  3779.  *     not drawn. Normally, when the Toolbox routine DrawGrowIcon is called, 
  3780.  *     vertical and horizontal lines are also drawn indicating where the 
  3781.  *     scrollbars will be drawn. We don’t have scrollbars, so we don’t want those 
  3782.  *     lines drawn. We avoid them by setting the clipping region of the window to 
  3783.  *     include the grow box only. We then call DrawGrowIcon, and restore the old 
  3784.  *     clipping region before returning.
  3785.  *
  3786.  *    Make sure that this gets called after the control strip for
  3787.  *    a window is drawn. 
  3788.  */
  3789.  
  3790. void    DoDrawGrowIcon(WindowPtr theWindow)
  3791. {
  3792.     Rect        iconRect;
  3793.     RgnHandle    oldClip;
  3794.     
  3795.  
  3796.     SetPort(theWindow);
  3797.     oldClip = NewRgn();
  3798.     GetClip(oldClip);
  3799.  
  3800.     iconRect = theWindow->portRect;
  3801.     iconRect.top = iconRect.bottom - 15;
  3802.     iconRect.left = iconRect.right - 15;
  3803.     ClipRect(&iconRect);
  3804.  
  3805.     PenNormal();
  3806.     DrawGrowIcon(theWindow);
  3807.  
  3808.     SetClip(oldClip);
  3809.     DisposeRgn(oldClip);
  3810. }
  3811.  
  3812.  
  3813. /*------------------------------------------------------------ */
  3814.  
  3815. /*
  3816.  * create a new viewer document window, this includes creating a
  3817.  * document record, a window and an associated viewer object.  the
  3818.  * document record is stored in the window's refcon field, so it
  3819.  * can be accessed as required via the window record.
  3820.  */
  3821.  
  3822. WindowPtr DoCreateNewViewerWindow( unsigned char *windowName )
  3823. {
  3824.     WindowPtr            theWindow ;
  3825.     Rect                myRect = { 0, 0, kWindHeight, kWindWidth } ;
  3826.     TQ3ViewerObject        myViewer ;
  3827.     DocumentHdl            myViewerDocument = NULL ;
  3828.     
  3829.     /* create a document record to hold the  */
  3830.     /* data for this instance  */
  3831.     if((myViewerDocument = (DocumentHdl)NewHandleClear(sizeof(Document))) == NULL)
  3832.         return NULL ;
  3833.     
  3834.     
  3835.     /* ideally we should stagger the rect  */
  3836.     OffsetRect( &myRect, 50, 50 ) ; 
  3837.                       
  3838.     theWindow = NewCWindow( NULL, 
  3839.                          &myRect, 
  3840.                          windowName, 
  3841.                          true, 
  3842.                          documentProc, 
  3843.                          (WindowPtr)-1, 
  3844.                          true, 
  3845.                          0L ) ;
  3846.                          
  3847.     /* create the viewer object associated with this window  */                   
  3848.     if((myViewer = Q3ViewerNew( (CGrafPtr)theWindow, 
  3849.                                 &theWindow->portRect, 
  3850.                                 kQ3ViewerDefault )) != NULL) 
  3851.     {
  3852.         ViewerDataHdl        myViewerData = (ViewerDataHdl)NewHandleClear(sizeof(ViewerData)) ;
  3853.         if(myViewerData == NULL)
  3854.         {
  3855.             DisposeHandle( (Handle)myViewerDocument ) ;
  3856.             return NULL ;
  3857.         }
  3858.         
  3859.         /* put the magic cookie in the first field so we can identify this as a valid viewer */
  3860.         (**myViewerDocument).fDocumentMagic = kViewerMagic ;
  3861.         
  3862.         /* set up the procs field */
  3863.         (**myViewerDocument).procs = &viewerProcs ;
  3864.         
  3865.         /* set up the private data part of the document structure */
  3866.         (**myViewerData).fViewer = myViewer ;
  3867.         
  3868.         /* stuff the handle in the viewerdata field */
  3869.         (**myViewerDocument).fPrivate = (void *) myViewerData ;
  3870.         
  3871.         /* store a reference to the document structure in the refcon
  3872.          * field of the window  
  3873.          */
  3874.         SetWRefCon( theWindow, (long)myViewerDocument ) ;
  3875.  
  3876.         /* finally create a new print record */
  3877.         DoCreatePrintRecord( myViewerDocument ) ;
  3878.  
  3879.     }
  3880.     else
  3881.     {
  3882.         /* clean up any allocates storage and quit  */
  3883.         if( myViewerDocument )
  3884.             DisposeHandle( (Handle)myViewerDocument ) ;
  3885.         
  3886.         if( theWindow ) 
  3887.             CloseWindow( theWindow ) ;
  3888.         
  3889.         theWindow = NULL ;
  3890.     }
  3891.     
  3892.     return theWindow ;
  3893. }
  3894.  
  3895. /*------------------------------------------------------------ */
  3896.  
  3897. /*
  3898.  * handles the New menu item in the file menu
  3899.  */
  3900.  
  3901.  
  3902. WindowPtr ViewerWindow_New( unsigned char *windowTitle )
  3903. {
  3904.     WindowPtr     theWindow ;    
  3905.     theWindow = DoCreateNewViewerWindow( windowTitle ) ;
  3906.     return theWindow ;
  3907. }
  3908.     
  3909. /*------------------------------------------------------------ */
  3910.  
  3911. /*
  3912.  * handles the Save As menu item in the file menu
  3913.  */
  3914.  
  3915.  
  3916. OSErr ViewerWindow_SaveAs( WindowPtr theWindow )
  3917. {
  3918.     OSErr                theError = paramErr ;
  3919.     short                theRef ;
  3920.  
  3921.     TQ3ViewerObject        theViewer ;
  3922.     StandardFileReply    theSFReply ;
  3923.     DocumentHdl            theDocumentHdl ;
  3924.  
  3925.  
  3926.     /* this option can't be selected unless there is a frontwindow  */
  3927.     /* the option is dimmed in adjustmenus if there is no window  */
  3928.     if( theWindow != NULL ) /* sanity check  */
  3929.     {
  3930.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3931.         if(theDocumentHdl != NULL
  3932.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic ) 
  3933.         {
  3934.             StandardPutFile("\pSave model as:", "\pUntitled", &theSFReply);
  3935.             if (theSFReply.sfGood)
  3936.             {
  3937.                 theError = FSpOpenDF(&theSFReply.sfFile, fsWrPerm, &theRef);
  3938.                 if (theError != noErr)
  3939.                 {
  3940.                     theError = FSpCreate(&theSFReply.sfFile, '????', '3DMF', theSFReply.sfScript);
  3941.                     if (theError == noErr)
  3942.                         theError = FSpOpenDF(&theSFReply.sfFile, fsCurPerm, &theRef);
  3943.                 }
  3944.                 if (theError == noErr)
  3945.                 {
  3946.                     /* get the viewer object from the document */
  3947.                     ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  3948.                     if( theViewerHdl != NULL )
  3949.                     {
  3950.                         HLock((Handle)theViewerHdl) ;
  3951.                         (**theViewerHdl).fFSSpec = theSFReply.sfFile ;
  3952.                         theViewer= (**theViewerHdl).fViewer ;
  3953.                         theError = Q3ViewerWriteFile(theViewer, (long)theRef);
  3954.                         theError = FSClose(theRef);
  3955.                         HUnlock((Handle)theViewerHdl) ;
  3956.                     }
  3957.                 }
  3958.                 
  3959.                 /* reset the window title  */
  3960.                 SetWTitle( theWindow, theSFReply.sfFile.name );
  3961.             }                    
  3962.         }
  3963.     }
  3964.     return theError ;
  3965. }
  3966.  
  3967. /*------------------------------------------------------------ */
  3968.  
  3969. /*
  3970.  * handles the Save menu item in the file menu
  3971.  */
  3972.  
  3973.  
  3974. OSErr ViewerWindow_Save( WindowPtr theWindow )
  3975. {
  3976.     OSErr                theError = paramErr ;
  3977.     short                theRef ;
  3978.  
  3979.     TQ3ViewerObject        theViewer ;
  3980.  
  3981.     DocumentHdl    theDocumentHdl ;
  3982.     FSSpec                theFSSpec ;
  3983.  
  3984.     /* this option can't be selected unless there is a frontwindow  */
  3985.     /* the option is dimmed in adjustmenus if there is no window  */
  3986.     if( theWindow != NULL )        /* sanity check  */
  3987.     {
  3988.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3989.         if(theDocumentHdl != NULL  
  3990.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  3991.         {
  3992.             /* get the viewer object from the document */
  3993.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  3994.             if( theViewerHdl != NULL )
  3995.             {
  3996.                 HLock((Handle)theViewerHdl) ;
  3997.                 theFSSpec = (**theViewerHdl).fFSSpec ;
  3998.                 /* open the file  */
  3999.                 theError = FSpOpenDF ( &theFSSpec, fsWrPerm, &theRef ) ;
  4000.                 if( theError == noErr ) 
  4001.                 {
  4002.                     if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4003.                     {
  4004.                         theError = Q3ViewerWriteFile( theViewer, (long)theRef );
  4005.                         if( theError == noErr )
  4006.                             theError = FSClose ( theRef ) ;
  4007.                     }
  4008.                 }
  4009.                 HUnlock((Handle)theViewerHdl) ;
  4010.             }
  4011.         }
  4012.     }
  4013.     return theError ;
  4014.             
  4015. }
  4016.         
  4017. /*------------------------------------------------------------ */
  4018.  
  4019. /*
  4020.  * handles the Revert menu item in the file menu
  4021.  */
  4022.  
  4023.  
  4024. OSErr ViewerWindow_Revert( WindowPtr theWindow )
  4025. {
  4026.     OSErr                theError = paramErr ;
  4027.     short                theRef ;
  4028.     GrafPtr                savedPort ;
  4029.  
  4030.     TQ3ViewerObject        theViewer ;
  4031.  
  4032.     DocumentHdl    theDocumentHdl ;
  4033.     FSSpec                theFSSpec ;
  4034.  
  4035.     /* this option can't be selected unless there is a frontwindow  */
  4036.     /* the option is dimmed in adjustmenus if there is no window  */
  4037.     if( theWindow != NULL )        /* sanity check  */
  4038.     {
  4039.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4040.         if(theDocumentHdl != NULL
  4041.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  4042.         {
  4043.             /* get the viewer object from the document */
  4044.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  4045.             if( theViewerHdl != NULL )
  4046.             {
  4047.                 HLock((Handle)theViewerHdl) ;
  4048.                 theFSSpec = (**theViewerHdl).fFSSpec ;
  4049.                 
  4050.                 /* open the file  */
  4051.                 theError = FSpOpenDF ( &theFSSpec, fsRdPerm, &theRef ) ;
  4052.                 if( theError == noErr ) 
  4053.                 {
  4054.                     if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4055.                     {
  4056.                         theError = Q3ViewerUseFile( theViewer, (long)theRef );
  4057.                         if( theError == noErr )
  4058.                             theError = FSClose ( theRef ) ;
  4059.                     }
  4060.                 }
  4061.  
  4062.                 HUnlock((Handle)theViewerHdl) ;
  4063.             }
  4064.         }
  4065.     }
  4066.     GetPort( &savedPort ) ;
  4067.     SetPort( (GrafPtr)theWindow ) ;
  4068.     InvalRect( &theWindow->portRect ) ;
  4069.     SetPort( savedPort ) ;
  4070.  
  4071.     return theError ;
  4072. }
  4073.  
  4074.  
  4075.     
  4076. WindowPtr ViewerWindow_Open( FSSpec *theFSSpec )
  4077. {
  4078.     OSErr                theError ;
  4079.     short                theRef ;
  4080.     WindowPtr            theWindow ;
  4081.     TQ3ViewerObject        theViewer ;
  4082.     DocumentHdl    theDocumentHdl ;
  4083.  
  4084.     /* open the file  */
  4085.     theError = FSpOpenDF( theFSSpec, fsRdPerm, &theRef ) ;
  4086.     
  4087.     if( theError == noErr )
  4088.     {                    
  4089.         theWindow = DoCreateNewViewerWindow( theFSSpec->name) ;
  4090.         
  4091.         if( theWindow != NULL )
  4092.         {
  4093.             
  4094.             theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4095.             if(theDocumentHdl != NULL 
  4096.                 && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  4097.             {
  4098.                 /* get the viewer object from the document */
  4099.                 ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  4100.                 if( theViewerHdl != NULL )
  4101.                 {
  4102.                     HLock((Handle)theViewerHdl) ;
  4103.                     if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4104.                     {
  4105.                         (**theViewerHdl).fFSSpec = *theFSSpec ;
  4106.                         theError = Q3ViewerUseFile( theViewer, theRef );
  4107.                         if( theError == noErr )
  4108.                             theError = FSClose ( theRef ) ;
  4109.                     }
  4110.                     HUnlock((Handle)theViewerHdl) ;
  4111.                 }
  4112.             }
  4113.         }
  4114.     }
  4115.     return theWindow ;
  4116. }    
  4117.         
  4118. /*------------------------------------------------------------ */
  4119.  
  4120. /*
  4121.  * handles the close menu item in the file menu
  4122.  * close the window after disposing of the associated
  4123.  * data structures (viewer, etc).
  4124.  */
  4125.  
  4126.  
  4127. OSErr ViewerWindow_Close( WindowPtr theWindow )
  4128. {
  4129.  
  4130.     OSErr                theError = paramErr ;
  4131.  
  4132.  
  4133.     TQ3ViewerObject        theViewer ;
  4134.  
  4135.     DocumentHdl    theDocumentHdl ;
  4136.  
  4137.  
  4138.     /* this option can't be selected unless there is a frontwindow  */
  4139.     /* the option is dimmed in adjustmenus if there is no window  */
  4140.     if( theWindow != NULL )        /* sanity check  */
  4141.     {
  4142.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4143.         if(theDocumentHdl != NULL 
  4144.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  4145.         {
  4146.             /* get the viewer object from the document */
  4147.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  4148.  
  4149.             /* dispose of the print record for the document */
  4150.             THPrint    thePrintRec = (**theDocumentHdl).fPrintRec ;
  4151.             if( thePrintRec != NULL )
  4152.                 DisposeHandle((Handle)thePrintRec ) ;
  4153.  
  4154.             if( theViewerHdl != NULL )
  4155.             {
  4156.                 HLock((Handle)theViewerHdl) ;
  4157.                 if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4158.                 {
  4159.                     theError = Q3ViewerDispose( theViewer ) ;
  4160.                     if( theError == noErr )
  4161.                         DisposeWindow( theWindow ) ;
  4162.                 }
  4163.                 HUnlock((Handle)theViewerHdl) ;
  4164.             }
  4165.         }
  4166.     }
  4167.     return theError ;
  4168.             
  4169. }
  4170. /*------------------------------------------------------------ */
  4171.  
  4172. /*
  4173.  * handle event for a viewer window
  4174.  */
  4175.  
  4176.  
  4177. Boolean    ViewerWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord)
  4178. {
  4179.  
  4180.     GrafPtr                savedPort ;
  4181.     short               thePart;
  4182.     Rect                screenRect;
  4183.     Rect                growRect ;
  4184.     Point                aPoint = {100, 100};
  4185.     GrafPtr                oldPort ;
  4186.     Boolean                eventWasHandled ;
  4187.     unsigned long        width ;
  4188.     unsigned long        height ;
  4189.     long                newSize ;
  4190.     OSErr                theErr ;
  4191.     Point                mouseLoc ;
  4192.     TQ3Boolean             handledEvent = kQ3False ;
  4193.     TQ3ViewerObject        theViewer = NULL ;
  4194.     DocumentHdl            theDocumentHdl ;
  4195.     ViewerDataHdl        theViewerHdl ;
  4196.       
  4197.       /* 
  4198.        * check to see if the event is a viewer event, also since
  4199.        * the update event processing needs to be done between begin update
  4200.        * and end update, don't handle updates here for viewer objects
  4201.        */
  4202.       if( theWindow != NULL && theEventRecord->what != updateEvt)
  4203.       {        
  4204.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4205.         if(theDocumentHdl != NULL) 
  4206.         {
  4207.             if((**theDocumentHdl).fDocumentMagic == kViewerMagic 
  4208.                 && ((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate))) != NULL
  4209.                 && (theViewer = (**theViewerHdl).fViewer) != NULL ) 
  4210.             {
  4211.                  /*
  4212.                    * There is a bug in versions 1.0.4 and earlier of the Viewer,
  4213.                    * so the port has to be set and restored.
  4214.                    */
  4215.                    
  4216.                 GetPort( &oldPort ) ;
  4217.                 SetPort((GrafPtr)theWindow ) ;
  4218.  
  4219.                 eventWasHandled = Q3ViewerEvent( theViewer, theEventRecord );
  4220.                 DoDrawGrowIcon(theWindow) ;
  4221.                 GetMouse( &mouseLoc ) ;
  4222.                 Q3ViewerAdjustCursor( theViewer,  &mouseLoc );
  4223.                 
  4224.                 /* restore the port */
  4225.                 SetPort( oldPort ) ;
  4226.                 
  4227.                 /* 
  4228.                  * if the window is not the frontmost 
  4229.                  * window, give the eventhandler 
  4230.                  * a chance to process the event.
  4231.                  */
  4232.                 if(theWindow != FrontWindow())
  4233.                     eventWasHandled = false ;
  4234.                     
  4235.             }
  4236.         }
  4237.         
  4238.     }
  4239.     else
  4240.     {
  4241.         eventWasHandled = false ;
  4242.     }
  4243.     return eventWasHandled ;
  4244. }
  4245.  
  4246.  
  4247. /*------------------------------------------------------------ */
  4248.  
  4249. /*
  4250.  * handle update for a viewer window
  4251.  */
  4252.  
  4253. void    ViewerWindow_Update(WindowPtr  theWindow)
  4254. {
  4255.     GrafPtr                oldPort ;
  4256.     DocumentHdl            theDocumentHdl ;
  4257.     ViewerDataHdl        theViewerHdl ;
  4258.     TQ3ViewerObject        theViewer ;
  4259.     OSErr                theErr ;
  4260.     
  4261.     GetPort( &oldPort ) ;    
  4262.     SetPort( theWindow );
  4263.     BeginUpdate( theWindow );
  4264.     {
  4265.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4266.         if(theDocumentHdl != NULL
  4267.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4268.             && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4269.         {
  4270.             if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4271.             {
  4272.                 theErr = Q3ViewerDraw( theViewer );
  4273.                 DoDrawGrowIcon(theWindow) ;
  4274.             }
  4275.         }
  4276.     }
  4277.     EndUpdate( theWindow );
  4278.     SetPort( oldPort ) ;
  4279. }
  4280.  
  4281. /*------------------------------------------------------------ */
  4282.  
  4283. /*
  4284.  * make sure that menus are enabled and disabled in an
  4285.  * appropriate manner for the case where the front window 
  4286.  * is a viewer window.
  4287.  */
  4288.  
  4289. void ViewerWindow_AdjustMenus( WindowPtr  theWindow )
  4290. {
  4291.         
  4292.     MenuHandle            theMenu ;
  4293.     DocumentHdl            theDocumentHdl ;
  4294.     ViewerDataHdl        theViewerHdl ;
  4295.     TQ3ViewerObject        theViewer ;
  4296.     TQ3ViewObject         myView ;
  4297.     TQ3Status            myStatus ;
  4298.     TQ3RendererObject    myRenderer ;
  4299.     TQ3ObjectType        theRendererType ;
  4300.     long                tmpLong, theScrapOffset ;
  4301.     unsigned long        theViewerFlags;
  4302.     unsigned long        theViewerState ;
  4303.     
  4304.     char                itemString[255] ;
  4305.     unsigned long        itemStringLength ;
  4306.  
  4307.     /*
  4308.      * get the reference to our viewer document data structure
  4309.      * from the long reference constant for the window.  Cast
  4310.      * it to the appropriate type.  If we can't get it (i.e. it's
  4311.      * null we want to bail
  4312.      */
  4313.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4314.     if(theDocumentHdl == NULL) 
  4315.         return ;
  4316.         
  4317.     /* get the reference to the viewer object from our data structure  */    
  4318.     if((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) == NULL)
  4319.         return ;
  4320.     
  4321.     /* get the reference to the viewer object from our data structure  */    
  4322.     theViewer = (**theViewerHdl).fViewer ;
  4323.     if(theViewer == NULL) 
  4324.         return ;
  4325.         
  4326.     /* get the viewer state, we need to know if it is empty  */    
  4327.     theViewerState = Q3ViewerGetState( theViewer ) ;
  4328.     
  4329.     /* adjust the file menu  */
  4330.     theMenu = GetMHandle ( mFileMenu ) ;
  4331.     
  4332.     EnableItem ( theMenu, iFileNewItem );        /* always enabled  */
  4333.     EnableItem ( theMenu, iFileOpenItem );        /* always enabled  */
  4334.     EnableItem ( theMenu, iFileQuitItem );        /* always enabled  */
  4335.  
  4336.     EnableItem ( theMenu, iFileCloseItem );
  4337.     
  4338.     if( ((theViewerState & kQ3ViewerHasModel) ? true : false ) ) 
  4339.     {
  4340.         EnableItem ( theMenu, iFileSaveItem );
  4341.         EnableItem ( theMenu, iFileSaveAsItem );
  4342.         EnableItem ( theMenu, iFileRevertItem );
  4343.         EnableItem ( theMenu, iFilePageSetupItem );
  4344.         EnableItem ( theMenu, iFilePrintItem );
  4345.     }
  4346.     else
  4347.     {
  4348.         DisableItem ( theMenu, iFileSaveItem );
  4349.         DisableItem ( theMenu, iFileSaveAsItem );
  4350.         DisableItem ( theMenu, iFileRevertItem );
  4351.         DisableItem ( theMenu, iFilePageSetupItem );
  4352.         DisableItem ( theMenu, iFilePrintItem );
  4353.     }
  4354.     
  4355.     
  4356.     /* adjust the edit menu  */
  4357.     theMenu = GetMHandle ( mEditMenu ) ;
  4358.     EnableItem ( theMenu, 0L );
  4359.     
  4360.     if( ((theViewerState & kQ3ViewerHasUndo) ? true : false ) ) 
  4361.     {
  4362.         /* undo is possible, get the string for this item and enable it */
  4363.         Boolean        canUndo ;
  4364.         
  4365.         /*
  4366.          * Hokeyness alert.  We pass in the address of the second element of 
  4367.          * the itemString array, allowing us to set the length later in the
  4368.          * first element of the array, saving us the need to to an inplace
  4369.          * C to P string conversion (the Mac toolbox routines require a 
  4370.          * pascal format string that has the length as the first byte.
  4371.          */
  4372.         canUndo = Q3ViewerGetUndoString( theViewer, &itemString[1], &itemStringLength );
  4373.         itemString[0] = (char)itemStringLength ;
  4374.                         
  4375.         /* if we can undo then enable the new string, else use the default cant undo string */
  4376.         if( canUndo == true && itemStringLength > 0 )
  4377.         {    
  4378.             SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  4379.             EnableItem ( theMenu, iEditUndoItem );
  4380.         }    
  4381.         else 
  4382.         {
  4383.             GetIndString ( (unsigned char *)itemString, 2223, 1 ) ;
  4384.             SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  4385.             DisableItem ( theMenu, iEditUndoItem );    
  4386.         }
  4387.     }
  4388.     else
  4389.     {
  4390.         GetIndString ( (unsigned char *)itemString, 2223, 1 ) ;
  4391.         SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  4392.         DisableItem ( theMenu, iEditUndoItem );    
  4393.     }
  4394.  
  4395.     if( ((theViewerState & kQ3ViewerHasModel) ? true : false ) ) 
  4396.     {
  4397.         EnableItem ( theMenu, iEditCutItem );
  4398.         EnableItem ( theMenu, iEditCopyItem );
  4399.         EnableItem ( theMenu, iEditClearItem );
  4400.     }
  4401.     else
  4402.     {
  4403.         DisableItem ( theMenu, iEditCutItem );
  4404.         DisableItem ( theMenu, iEditCopyItem );
  4405.         DisableItem ( theMenu, iEditClearItem );
  4406.     }
  4407.     
  4408.     
  4409.     /*
  4410.      * check that there is some data that we can paste.  GetScrap returns
  4411.      * a long that gives either the length of the requested type, or a
  4412.      * negative error code that is used to indicate that no such type exists
  4413.      */
  4414.     
  4415.     tmpLong = GetScrap( NULL, '3DMF', &theScrapOffset ) ;
  4416.     if( tmpLong < 0 )
  4417.         DisableItem ( theMenu, iEditPasteItem );
  4418.     else
  4419.         EnableItem ( theMenu, iEditPasteItem );
  4420.         
  4421.  
  4422.     
  4423.     /* adjust the view menu  */
  4424.     theMenu = GetMHandle ( mViewMenu ) ;
  4425.     EnableItem ( theMenu, 0L );
  4426.     
  4427.     /*
  4428.      * since most of the items in this menu rely on adjusting
  4429.      * the viewer flags, we'll get the flags here so we can
  4430.      * bitwise manipulate them in the switch below
  4431.      */ 
  4432.     theViewerFlags = Q3ViewerGetFlags( theViewer ) ;
  4433.     
  4434.     /*
  4435.      * check each of the items that have their flag
  4436.      * bits set to true in the viewer flags.
  4437.      *
  4438.      * Note that the Boolean flag for CheckItem is defined
  4439.      * (( theViewerFlags & kQ3ViewerShowBadge ) ? true : false)
  4440.      * and so on.  The reson for this is that simply adding
  4441.      * ( theViewerFlags & kQ3ViewerShowBadge ) won't be sufficient
  4442.      * if the flag is the 8th bit or more of the unsigned long 
  4443.      * defined to hold the flages, since the param passed will 
  4444.      * only be the first 8 bits (of couse this is dependent on
  4445.      * the develolment system size for Boolean, but this is true
  4446.      * for CodeWarrior.
  4447.      */
  4448.     
  4449.     CheckItem( theMenu, iViewBadgeItem, (( theViewerFlags & kQ3ViewerShowBadge ) ? true : false)) ;
  4450.     CheckItem( theMenu, iViewCameraButtonItem, (( theViewerFlags & kQ3ViewerButtonCamera ) ? true : false)) ;
  4451.     CheckItem( theMenu, iViewTruckButtonItem, (( theViewerFlags & kQ3ViewerButtonTruck ) ? true : false)) ;
  4452.     CheckItem( theMenu, iViewOrbitButtonItem, (( theViewerFlags & kQ3ViewerButtonOrbit ) ? true : false)) ;
  4453.     CheckItem( theMenu, iViewZoomButtonItem, (( theViewerFlags & kQ3ViewerButtonZoom ) ? true : false)) ;
  4454.     CheckItem( theMenu, iViewDollyButtonItem, (( theViewerFlags & kQ3ViewerButtonDolly ) ? true : false)) ;
  4455.     CheckItem( theMenu, iViewInsetNFrameItem, (( theViewerFlags & kQ3ViewerDrawFrame ) ? true : false)) ;
  4456.     
  4457.     /* adjust the renderer menu  */
  4458.     theMenu = GetMHandle ( mInteractiveRendererMenu ) ;
  4459.     
  4460.     /*
  4461.      * get the renderer for the view
  4462.      */
  4463.     myView = Q3ViewerGetView( theViewer );
  4464.     if( myView != NULL )
  4465.     {
  4466.         long                    rendererIndex = 0 ;
  4467.         MenuHandle                tempMenu ;
  4468.         
  4469.         /* set the renderer to the one created in the switch statement above */
  4470.         myStatus = Q3View_GetRenderer(myView, &myRenderer) ;
  4471.         theRendererType = Q3Renderer_GetType( myRenderer ) ;
  4472.         
  4473.         for( rendererIndex = 0; pInteractiveTypes[ rendererIndex ] ; rendererIndex++ ) 
  4474.         {
  4475.             CheckItem( theMenu, rendererIndex+1,  (theRendererType == pInteractiveTypes[rendererIndex])) ;
  4476.         }
  4477.         
  4478.         /*
  4479.          * Update the edit renderer prefs "edit menu" item.  Should probably be done with 
  4480.          * the edit menu stuff, I put this here because we have a reference
  4481.          * to the renderer here
  4482.          */
  4483.                 
  4484.         /* enable the menu item appropriately */
  4485.         tempMenu = GetMHandle ( mEditMenu ) ;
  4486.         if( Q3Renderer_HasModalConfigure(myRenderer) )
  4487.             EnableItem ( tempMenu, iEditRendererPrefsItem );
  4488.         else
  4489.             DisableItem ( tempMenu, iEditRendererPrefsItem );
  4490.  
  4491.         /* 
  4492.          * getting the renderer incremented the ref count for it,
  4493.          * we can dispose of the reference to it 
  4494.          */
  4495.         myStatus = Q3Object_Dispose( myRenderer ) ;            
  4496.     }
  4497. }
  4498.  
  4499. /*------------------------------------------------------------ */
  4500.  
  4501. /*
  4502.  * ViewerWindow_CountPages - calculate the number of pages needed to
  4503.  * image the document associated with the viewer window.  For now we
  4504.  * assume 1.
  4505.  */
  4506.  
  4507.  
  4508. short    ViewerWindow_CountPages( 
  4509.     WindowPtr    theWindow, 
  4510.     Rect         *pageRect ) 
  4511. {
  4512.     Rect            pictRect ;
  4513.     short            horizOffset, 
  4514.                     vertOffset,
  4515.                     pagesWide = 0,     /*  the number of pages wide the image is */
  4516.                     pagesHigh = 0,     /*  the number pages high for this image */
  4517.                     pageWidth,         /*  the width of one page */
  4518.                     pageHeight ;    /*  the height of one page */
  4519.  
  4520.     DocumentHdl        theDocumentHdl ;
  4521.     ViewerDataHdl    theViewerHdl ;
  4522.     GWorldPtr        theGWorld ;
  4523.     OSErr            theErr ;
  4524.     
  4525.     short            retVal = 0 ;
  4526.     
  4527.     PicHandle        thePicture ;
  4528.     
  4529.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4530.     if(theDocumentHdl != NULL
  4531.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4532.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4533.     {
  4534.         if((theGWorld = (**theViewerHdl).fGWorld) != NULL) 
  4535.         {
  4536.             retVal = GeneralCountPages( theGWorld, pageRect ) ;
  4537.         }
  4538.     }
  4539.     
  4540.     return retVal ;
  4541. }
  4542.  
  4543. /*------------------------------------------------------------ */
  4544.  
  4545. /*
  4546.  * ViewerWindow_PrintPage - image the requested page in the 
  4547.  * printer port
  4548.  */
  4549.  
  4550. void    ViewerWindow_PrintPage( 
  4551.     WindowPtr         theWindow, 
  4552.     Rect             *pageRect, 
  4553.     GrafPtr         imagingPort, 
  4554.     short             pageNum ) 
  4555. {
  4556.     GWorldPtr        theGWorld;
  4557.     Rect            pictRect, rectToPrint,srcRect,dstRect;
  4558.     short            pagesWide,         /*  the number of pages wide the image is */
  4559.                     pagesHigh,         /*  the number pages high for this image */
  4560.                     horozTile,         /*  used in the loop to denote the H tile to print from the image */
  4561.                     vertTile ;         /*  used in the loop to denote the V tile to print from the image */
  4562.     short            thisPage = 1;    /*  used to find the page they want us to print */
  4563.     short            pictHOff,
  4564.                     pictVOff,
  4565.                     pictWidth,         /*  the width of the doc's GWorld */
  4566.                     pictHeight ;    /*  the height of the doc's GWorld */
  4567.     short            pageWidth,         /*  the width of one page */
  4568.                     pageHeight ;    /*  the height of one page */
  4569.     OSErr            theErr ;
  4570.     PixMapHandle    offPixMap ;
  4571.     DocumentHdl        theDocumentHdl ;
  4572.     ViewerDataHdl    theViewerHdl ;
  4573.     TQ3ViewerObject    theViewer ;
  4574.  
  4575.  
  4576.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4577.     if(theDocumentHdl != NULL
  4578.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4579.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4580.     {
  4581.         if((theGWorld = (**theViewerHdl).fGWorld) != NULL) 
  4582.         {
  4583.             GeneralPrintPage( theGWorld, pageRect, imagingPort, pageNum ) ;
  4584.         }
  4585.     }
  4586. }
  4587.  
  4588.  
  4589. /*------------------------------------------------------------ */
  4590.  
  4591. /*
  4592.  * ViewerWindow_PrePrint - this gets called before we print, so any
  4593.  * setup for printing can be done here.
  4594.  */
  4595. void ViewerWindow_PrePrint( WindowPtr theWindow )
  4596. {
  4597.     /*
  4598.      * before we print we want to get a pixmap that represents the 
  4599.      * current document being imaged.  We use Q3ViewerGetPict to 
  4600.      * do this and use the fGWorld field of the viewer's data
  4601.      * to store this until it's been imaged.  Not efficient, but
  4602.      * that's the price of using the viewer.
  4603.      */
  4604.     DocumentHdl            theDocumentHdl ;
  4605.     ViewerDataHdl        theViewerHdl ;
  4606.     TQ3ViewerObject        theViewer ;
  4607.  
  4608.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4609.     if(theDocumentHdl != NULL
  4610.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4611.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4612.     {
  4613.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4614.         {
  4615.             PicHandle        thePicture ;
  4616.             GWorldPtr        theGWorld ;
  4617.             Rect            pictRect ;
  4618.             OSErr            theErr ;
  4619.             GrafPtr            savedPort ;
  4620.             
  4621.             GetPort( &savedPort ) ;
  4622.             SetPort( (GrafPtr) theWindow ) ;
  4623.             
  4624.             thePicture = Q3ViewerGetPict( theViewer ) ;
  4625.             
  4626.             SetPort( savedPort ) ;
  4627.             
  4628.             if( thePicture != NULL )
  4629.             {
  4630.                 pictRect.top    = (**thePicture).picFrame.top ;
  4631.                 pictRect.left    = (**thePicture).picFrame.left ;
  4632.                 pictRect.bottom    = (**thePicture).picFrame.bottom ;
  4633.                 pictRect.right    = (**thePicture).picFrame.right ;
  4634.                 
  4635.                 /* make sure the GWorld's origin is (0,0) */
  4636.                 OffsetRect( &pictRect, -pictRect.left, -pictRect.top ) ;
  4637.                 
  4638.                 /* make a new offscreen world */
  4639.                 theErr =  NewGWorld( &theGWorld, 32, &pictRect, NULL, NULL, 0L );
  4640.                 if( theErr == noErr && theGWorld != NULL )
  4641.                 {
  4642.                     PixMapHandle            offPixMap ;
  4643.                     CGrafPtr                savedPort ;
  4644.                     GDHandle                gdh ;
  4645.                     
  4646.                     /* image the picture into the offscreen */
  4647.                     GetGWorld( &savedPort, &gdh ) ;
  4648.                     SetGWorld( theGWorld, NULL ) ;
  4649.                     
  4650.                     /* get the gworld pixmap and lock it down */
  4651.                     offPixMap = GetGWorldPixMap( theGWorld ) ;
  4652.                     (void) LockPixels( offPixMap ) ;
  4653.                 
  4654.                     /* draw the Picture in the port */
  4655.                     DrawPicture( thePicture, &theGWorld->portRect ) ;
  4656.                     
  4657.                     /* unlock the pixmap */
  4658.                     (void) UnlockPixels( offPixMap ) ;
  4659.                         
  4660.                     SetGWorld( savedPort, gdh ) ;
  4661.                     (**theViewerHdl).fGWorld = theGWorld;
  4662.                 
  4663.                 }
  4664.                 else
  4665.                 {
  4666.                     (**theViewerHdl).fGWorld = NULL;
  4667.                 }
  4668.                 
  4669.                 /* ditch the pict */
  4670.                 KillPicture( thePicture ) ;
  4671.  
  4672.             }
  4673.             else
  4674.             {
  4675.                 (**theViewerHdl).fGWorld = NULL ;
  4676.             }
  4677.         }
  4678.     }
  4679.      
  4680.     return ; 
  4681. }
  4682.  
  4683.  
  4684. /*------------------------------------------------------------ */
  4685.  
  4686. /*
  4687.  * ViewerWindow_PostPrint - this gets called before we print, so any
  4688.  * setup for printing can be done here.
  4689.  */
  4690. void ViewerWindow_PostPrint( WindowPtr theWindow )
  4691. {
  4692.     /* delete the cached pict */
  4693.     DocumentHdl            theDocumentHdl ;
  4694.     ViewerDataHdl        theViewerHdl ;
  4695.     TQ3ViewerObject        theViewer ;
  4696.  
  4697.  
  4698.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4699.     if(theDocumentHdl != NULL
  4700.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4701.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4702.     {
  4703.         GWorldPtr        theGWorld = (**theViewerHdl).fGWorld ;
  4704.         
  4705.         /* get rid of the gworld */
  4706.         DisposeGWorld(theGWorld);
  4707.         (**theViewerHdl).fGWorld = NULL ;
  4708.     }
  4709.      
  4710.     return ; 
  4711. }
  4712.  
  4713. /*------------------------------------------------------------ */
  4714.  
  4715. /*
  4716.  * Handle the edit menu cut command for this window type
  4717.  */
  4718. OSErr        ViewerWindow_Cut( WindowPtr    theWindow ) 
  4719. {
  4720.     DocumentHdl            theDocumentHdl ;
  4721.     ViewerDataHdl        theViewerHdl ;
  4722.     TQ3ViewerObject        theViewer ;
  4723.     OSErr                theError = paramErr ;
  4724.  
  4725.  
  4726.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4727.     if(theDocumentHdl != NULL
  4728.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4729.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4730.     {
  4731.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4732.         {
  4733.             theError = Q3ViewerCut ( theViewer ) ;
  4734.         }
  4735.     }
  4736.      
  4737.     return theError ; 
  4738.  
  4739. }
  4740.  
  4741. /*------------------------------------------------------------ */
  4742.  
  4743. /*
  4744.  * Handle the edit menu copy command for this window type
  4745.  */
  4746. OSErr        ViewerWindow_Copy( WindowPtr    theWindow ) 
  4747. {
  4748.  
  4749.     DocumentHdl            theDocumentHdl ;
  4750.     ViewerDataHdl        theViewerHdl ;
  4751.     TQ3ViewerObject        theViewer ;
  4752.     OSErr                theError = paramErr ;
  4753.  
  4754.  
  4755.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4756.     if(theDocumentHdl != NULL
  4757.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4758.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4759.     {
  4760.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4761.         {
  4762.             theError = Q3ViewerCopy ( theViewer ) ;
  4763.         }
  4764.     }
  4765.      
  4766.     return theError ; 
  4767.  
  4768. }
  4769.  
  4770. /*------------------------------------------------------------ */
  4771.  
  4772. /*
  4773.  * Handle the edit menu paste command for this window type
  4774.  */
  4775. OSErr        ViewerWindow_Paste( WindowPtr    theWindow ) 
  4776. {
  4777.  
  4778.     DocumentHdl            theDocumentHdl ;
  4779.     ViewerDataHdl        theViewerHdl ;
  4780.     TQ3ViewerObject        theViewer ;
  4781.     OSErr                theError = paramErr ;
  4782.  
  4783.  
  4784.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4785.     if(theDocumentHdl != NULL
  4786.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4787.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4788.     {
  4789.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4790.         {
  4791.             theError = Q3ViewerPaste ( theViewer ) ;
  4792.         }
  4793.     }
  4794.      
  4795.     return theError ; 
  4796.  
  4797. }
  4798.  
  4799. /*------------------------------------------------------------ */
  4800.  
  4801. /*
  4802.  * Handle the edit menu clear command for this window type
  4803.  */
  4804. OSErr        ViewerWindow_Clear( WindowPtr    theWindow )
  4805. {
  4806.  
  4807.     DocumentHdl            theDocumentHdl ;
  4808.     ViewerDataHdl        theViewerHdl ;
  4809.     TQ3ViewerObject        theViewer ;
  4810.     OSErr                theError = paramErr ;
  4811.  
  4812.  
  4813.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4814.     if(theDocumentHdl != NULL
  4815.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4816.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4817.     {
  4818.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4819.         {
  4820.             theError = Q3ViewerClear ( theViewer ) ;
  4821.         }
  4822.     }
  4823.      
  4824.     return theError ; 
  4825.  
  4826. }
  4827.  
  4828. /*------------------------------------------------------------ */
  4829.  
  4830. /*
  4831.  * Handle the edit menu undo command for this window type
  4832.  */
  4833. OSErr        ViewerWindow_Undo( WindowPtr    theWindow )
  4834. {
  4835.  
  4836.     DocumentHdl            theDocumentHdl ;
  4837.     ViewerDataHdl        theViewerHdl ;
  4838.     TQ3ViewerObject        theViewer ;
  4839.     OSErr                theError = paramErr ;
  4840.  
  4841.  
  4842.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4843.     if(theDocumentHdl != NULL
  4844.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4845.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4846.     {
  4847.         theError = Q3ViewerUndo ( theViewer ) ;
  4848.     }
  4849.      
  4850.     return theError ; 
  4851.  
  4852. }
  4853.  
  4854. /*------------------------------------------------------------ */
  4855.  
  4856. /*
  4857.  * Get an output reference for a PICT file
  4858.  */
  4859. OSErr GetOutputPictFileRef(short    *dstPictFRef ) 
  4860. {
  4861.     StandardFileReply    aPictSFR;    /* new style Standard file record */
  4862.     OSErr                result ;
  4863.     SFTypeList     types = { 'PICT',0 };    /* we are only interested in PICT files */
  4864.         
  4865.     StandardPutFile( "\pSave PICT as:", "\pNew PICT", &aPictSFR ) ;
  4866.     if ( aPictSFR.sfGood  ) {
  4867.         
  4868.         /* 
  4869.          * Delete the file of the same name, if one exits, 
  4870.          * and create a new PICT file.
  4871.          */
  4872.         
  4873.         FSpDelete(&aPictSFR.sfFile);
  4874.         
  4875.         result = FSpCreate( &aPictSFR.sfFile,'????','PICT', aPictSFR.sfScript);
  4876.         if (result != noErr) {
  4877.             return result;
  4878.         }
  4879.         
  4880.         /* open the data fork for writing */
  4881.         
  4882.         result = FSpOpenDF( &aPictSFR.sfFile, fsCurPerm, dstPictFRef);
  4883.         if (result != noErr) {
  4884.             return result;
  4885.         }
  4886.     }
  4887.     else 
  4888.         return userCanceledErr ;
  4889.         
  4890.     return noErr ;
  4891. }
  4892.  
  4893. /*------------------------------------------------------------ */
  4894.  
  4895. /*
  4896.  * create a new viewer document window, this includes creating a
  4897.  * document record, a window and an associated viewer object.  the
  4898.  * document record is stored in the window's refcon field, so it
  4899.  * can be accessed as required via the window record.
  4900.  */
  4901.  
  4902. WindowPtr DoCreateNewPictWindow( unsigned char *windowName, long windWidth, long windHeight )
  4903. {
  4904.     WindowPtr            theWindow ;
  4905.     Rect                myRect ;
  4906.     TQ3ViewerObject        myViewer ;
  4907.     DocumentHdl            myPictDocument = NULL ;
  4908.     GWorldPtr            myGWorld ;
  4909.     PictDataHdl        myViewerPict ;
  4910.     
  4911.     myRect.top = 0 ;
  4912.     myRect.left = 0 ;
  4913.     myRect.bottom = windHeight ;
  4914.     myRect.right = windWidth ;
  4915.  
  4916.     /* create a document record to hold the  */
  4917.     /* data for this instance  */
  4918.     if((myPictDocument = (DocumentHdl)NewHandleClear(sizeof(Document))) == NULL)
  4919.         return NULL ;
  4920.     
  4921.     /* make a GWorld the size requested */
  4922.     if(NewGWorld ( &myGWorld, 32, &myRect, NULL, NULL, 0L ) != noErr)
  4923.         return NULL ;
  4924.         
  4925.     
  4926.     /* ideally we should stagger the window rect  */
  4927.     
  4928.     OffsetRect( &myRect, 50, 50 ) ; 
  4929.                       
  4930.     theWindow = NewCWindow( NULL, 
  4931.                          &myRect, 
  4932.                          windowName, 
  4933.                          true, 
  4934.                          documentProc, 
  4935.                          (WindowPtr)-1, 
  4936.                          true, 
  4937.                          0L ) ;
  4938.                          
  4939.     myViewerPict = (PictDataHdl)NewHandleClear(sizeof(PictData)) ;
  4940.     if(myViewerPict == NULL)
  4941.     {
  4942.         DisposeHandle( (Handle)myPictDocument ) ;
  4943.         return NULL ;
  4944.     }
  4945.         
  4946.     /* put the magic cookie in the first field so we can identify this as a valid pict */
  4947.     (**myPictDocument).fDocumentMagic = kPICTMagic ;
  4948.     
  4949.     /* set up the procs field */
  4950.     (**myPictDocument).procs = &pictProcs ;
  4951.     
  4952.     /* set up the private data part of the document structure */
  4953.     (**myViewerPict).fGWorld = myGWorld ;
  4954.     
  4955.     (**myPictDocument).fPrivate = (void *)myViewerPict ;
  4956.     
  4957.     /* finally create a new print record */
  4958.     DoCreatePrintRecord( myPictDocument ) ;
  4959.  
  4960.     /* store a reference to the document structure in the refcon
  4961.      * field of the window  
  4962.      */
  4963.     SetWRefCon( theWindow, (long)myPictDocument ) ;
  4964.     
  4965.     return theWindow ;
  4966. }
  4967.  
  4968.  
  4969. /*------------------------------------------------------------ */
  4970.  
  4971. /*
  4972.  * PictWindow_Update
  4973.  */
  4974. void            PictWindow_Update( WindowPtr  theWindow ) 
  4975. {
  4976.     GrafPtr                oldPort ;
  4977.     DocumentHdl            theDocumentHdl ;
  4978.     PictDataHdl            thePictDataHdl ;
  4979.     GWorldPtr            theGWorld ;
  4980.     OSErr                theErr ;
  4981.     
  4982.     GetPort( &oldPort ) ;    
  4983.     SetPort( theWindow );
  4984.     BeginUpdate( theWindow );
  4985.  
  4986.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4987.     if(theDocumentHdl != NULL
  4988.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  4989.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4990.     {
  4991.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  4992.         {
  4993.             /* copybits from the GWorld here */
  4994.             
  4995.             CopyBits ((BitMapPtr) &theGWorld->portPixMap,
  4996.                       &theWindow->portBits,
  4997.                       &theGWorld->portRect, 
  4998.                       &theWindow->portRect,
  4999.                       srcCopy, 
  5000.                       0L);
  5001.             DoDrawGrowIcon(theWindow) ;
  5002.         }
  5003.     }
  5004.     
  5005.     EndUpdate( theWindow );
  5006.     SetPort( oldPort ) ;
  5007. }
  5008.  
  5009.  
  5010. /*------------------------------------------------------------ */
  5011.  
  5012. /*
  5013.  * PictWindow_AdjustMenus
  5014.  */
  5015. void             PictWindow_AdjustMenus( WindowPtr  theWindow ) 
  5016. {
  5017.         
  5018.     MenuHandle            theMenu ;
  5019.     DocumentHdl            theDocumentHdl ;
  5020.     ViewerDataHdl        theViewerHdl ;
  5021.     TQ3ViewerObject        theViewer ;
  5022.     TQ3ViewObject         myView ;
  5023.     TQ3Status            myStatus ;
  5024.     TQ3RendererObject    myRenderer ;
  5025.     TQ3ObjectType        theRendererType ;
  5026.     long                tmpLong, theScrapOffset ;
  5027.     unsigned long        theViewerFlags;
  5028.     unsigned long        theViewerState ;
  5029.     
  5030.     char                itemString[255] ;
  5031.     unsigned long        itemStringLength ;
  5032.  
  5033.     /*
  5034.      * get the reference to our Pict document data structure
  5035.      * from the long reference constant for the window.  Cast
  5036.      * it to the appropriate type.  If we can't get it (i.e. it's
  5037.      * null we want to bail
  5038.      */
  5039.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  5040.     if(theDocumentHdl == NULL) 
  5041.         return ;
  5042.         
  5043.     /* adjust the file menu  */
  5044.     theMenu = GetMHandle ( mFileMenu ) ;
  5045.     
  5046.     EnableItem ( theMenu, iFileNewItem );        /* always enabled  */
  5047.     EnableItem ( theMenu, iFileOpenItem );        /* always enabled  */
  5048.     EnableItem ( theMenu, iFileQuitItem );        /* always enabled  */
  5049.  
  5050.     EnableItem ( theMenu, iFileCloseItem );
  5051.     
  5052.     /* 
  5053.      * this only gets called if we have a pict window in the first 
  5054.      * place so enable saving and printing...
  5055.      */
  5056.     EnableItem ( theMenu, iFileSaveItem );
  5057.     EnableItem ( theMenu, iFileSaveAsItem );
  5058.     EnableItem ( theMenu, iFileRevertItem );
  5059.     EnableItem ( theMenu, iFilePageSetupItem );
  5060.     EnableItem ( theMenu, iFilePrintItem );
  5061.  
  5062.     /* adjust the edit menu  */
  5063.     theMenu = GetMHandle ( mEditMenu ) ;
  5064.     EnableItem ( theMenu, 0L );
  5065.     
  5066.     /* 
  5067.      * there's not really anything to undo with this window type so set 
  5068.      * the undo string to "Can't Undo"
  5069.      */
  5070.     GetIndString ( (unsigned char *)itemString, 2223, 1 ) ;
  5071.     SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  5072.     
  5073.     
  5074.     DisableItem ( theMenu, iEditUndoItem );    
  5075.  
  5076.     /* enable copy */
  5077.     EnableItem ( theMenu, iEditCopyItem );
  5078.     
  5079.     /* disable cut, paste and clear */
  5080.     DisableItem ( theMenu, iEditClearItem );
  5081.     DisableItem ( theMenu, iEditPasteItem );
  5082.     DisableItem ( theMenu, iEditCutItem );
  5083.     
  5084.     /* disable the renderer prefs */
  5085.     DisableItem ( theMenu, iEditRendererPrefsItem );
  5086.                 
  5087.     /* adjust the view menu  */
  5088.     theMenu = GetMHandle ( mViewMenu ) ;
  5089.     DisableItem ( theMenu, 0L );
  5090.     
  5091.     return ;
  5092. }
  5093.  
  5094.  
  5095. /*------------------------------------------------------------ */
  5096.  
  5097. /*
  5098.  * PictWindow_HandleEvent
  5099.  */
  5100. Boolean            PictWindow_HandleEvent( WindowPtr theWindow, EventRecord *theEventRecord) 
  5101. {
  5102.     return false ;
  5103. }
  5104.  
  5105.  
  5106. /*------------------------------------------------------------ */
  5107.  
  5108. /*
  5109.  * PictWindow_New
  5110.  */
  5111. WindowPtr         PictWindow_New( unsigned char *windowTitle ) 
  5112. {
  5113.     return NULL ;
  5114. }
  5115.  
  5116.  
  5117. /*------------------------------------------------------------ */
  5118.  
  5119. /*
  5120.  * PictWindow_SaveAs
  5121.  */
  5122. OSErr             PictWindow_SaveAs( WindowPtr theWindow ) 
  5123. {
  5124.     short                dstPictFRef = 0 ;
  5125.     PicHandle            thePicture = NULL ;
  5126.     OSErr                theErr = noErr ;
  5127.     GWorldPtr            theGWorld ;
  5128.     CGrafPtr            savedPort ;
  5129.     GDHandle            savedGDH ;
  5130.     
  5131.     /* get an open a file for writing */
  5132.     if( (theErr = GetOutputPictFileRef( &dstPictFRef )) == noErr ) {
  5133.     
  5134.         theGWorld = GetGWorldFromPictWindow( theWindow ) ;
  5135.         
  5136.         /* make a temp viewer to use to make the PICT */
  5137.         if( theGWorld != NULL )
  5138.         {
  5139.             
  5140.             /* lock the viewer's GWorld for updates */
  5141.             LockPixels(GetGWorldPixMap(theGWorld)) ;
  5142.  
  5143.             GetGWorld( &savedPort, &savedGDH ) ;
  5144.             SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  5145.         
  5146.             thePicture = OpenPicture(&theGWorld->portRect) ;
  5147.             
  5148.             /* copy onto ourselves to make the picture */
  5149.             CopyBits ((BitMapPtr) &theGWorld->portPixMap,
  5150.                       (BitMapPtr) &theGWorld->portPixMap,
  5151.                       &theGWorld->portRect, 
  5152.                       &theGWorld->portRect, 
  5153.                       srcCopy, 
  5154.                       0L);
  5155.  
  5156.             ClosePicture() ;
  5157.         
  5158.             if( thePicture  != NULL ) {
  5159.  
  5160.                  long                    length ;
  5161.                 long                    dummy ;
  5162.                 long                    index ;
  5163.  
  5164.                  /* ok, myPic now contains a handle to the picture */
  5165.                 HLock( (Handle)thePicture);
  5166.  
  5167.                 /* set up the 512 byte header for a PICT file */
  5168.                 dummy = 0;
  5169.                 
  5170.                 for( index = 0; index < ( 512 / 4 ); index ++ ){
  5171.                     length = 4 ;
  5172.                        
  5173.                        if( (theErr = FSWrite(dstPictFRef, &length, &dummy)) != noErr ) {
  5174.                         return theErr ;        
  5175.                     }
  5176.                 }                
  5177.                 
  5178.                    length = GetHandleSize( (Handle)thePicture);
  5179.                   
  5180.                    if( (theErr = FSWrite(dstPictFRef, &length, *thePicture)) != noErr ) {
  5181.                     return theErr ;        
  5182.                 }
  5183.              
  5184.                    /* now get rid of the picture handle */
  5185.                 HUnlock( (Handle) thePicture ) ;
  5186.                    KillPicture(thePicture);         
  5187.                 FSClose(dstPictFRef);
  5188.             }
  5189.         }
  5190.     }
  5191.     
  5192.     return theErr ;
  5193. }
  5194.  
  5195.  
  5196. /*------------------------------------------------------------ */
  5197.  
  5198. /*
  5199.  * PictWindow_Save
  5200.  */
  5201. OSErr             PictWindow_Save( WindowPtr theWindow ) 
  5202. {
  5203.     /* we don't really work well with pictures so just call save as */
  5204.     PictWindow_SaveAs( theWindow ) ;
  5205. }
  5206.  
  5207.  
  5208. /*------------------------------------------------------------ */
  5209.  
  5210. /*
  5211.  * PictWindow_Revert
  5212.  */
  5213. OSErr             PictWindow_Revert( WindowPtr theWindow ) 
  5214. {
  5215.     return noErr ;
  5216. }
  5217.  
  5218.  
  5219. /*------------------------------------------------------------ */
  5220.  
  5221. /*
  5222.  * PictWindow_Open
  5223.  */
  5224. WindowPtr         PictWindow_Open( FSSpec *theFSSpec ) 
  5225. {
  5226.     return NULL ;
  5227. }
  5228.  
  5229. /*------------------------------------------------------------ */
  5230.  
  5231. /*
  5232.  * PictWindow_Close
  5233.  */
  5234. OSErr PictWindow_Close( WindowPtr theWindow ) 
  5235. {
  5236.     DocumentHdl            theDocumentHdl ;
  5237.     PictDataHdl            thePictDataHdl ;
  5238.     GWorldPtr            theGWorld ;
  5239.     OSErr                theErr ;
  5240.     THPrint                thePrintRec ;
  5241.     
  5242.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  5243.     if(theDocumentHdl != NULL
  5244.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  5245.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  5246.     {
  5247.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  5248.         {
  5249.             DisposeGWorld( theGWorld ) ;
  5250.         }
  5251.         DisposeHandle((Handle)thePictDataHdl) ;
  5252.  
  5253.         thePrintRec = (**theDocumentHdl).fPrintRec ;
  5254.         if( thePrintRec != NULL )
  5255.             DisposeHandle((Handle)thePrintRec ) ;
  5256.  
  5257.         DisposeHandle((Handle)theDocumentHdl) ;
  5258.         
  5259.     }
  5260.     DisposeWindow( theWindow ) ;
  5261.     return noErr ;
  5262. }
  5263.  
  5264.  
  5265. /*------------------------------------------------------------ */
  5266.  
  5267. /*
  5268.  * PictWindow_CountPages - calculate the number of pages needed to
  5269.  * image the document associated with the picture window
  5270.  */
  5271.  
  5272. short    PictWindow_CountPages( 
  5273.     WindowPtr    theWindow, 
  5274.     Rect         *pageRect ) 
  5275. {
  5276.     Rect            pictRect ;
  5277.     short            horizOffset, 
  5278.                     vertOffset,
  5279.                     pagesWide = 0,     /*  the number of pages wide the image is */
  5280.                     pagesHigh = 0,     /*  the number pages high for this image */
  5281.                     pageWidth,         /*  the width of one page */
  5282.                     pageHeight ;    /*  the height of one page */
  5283.  
  5284.     DocumentHdl        theDocumentHdl ;
  5285.     PictDataHdl        thePictDataHdl ;
  5286.     GWorldPtr        theGWorld ;
  5287.     OSErr            theErr ;
  5288.     short            retVal = 0 ;
  5289.     
  5290.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  5291.     if(theDocumentHdl != NULL
  5292.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  5293.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  5294.     {
  5295.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  5296.         {
  5297.             retVal = GeneralCountPages( theGWorld, pageRect ) ;        
  5298.         }
  5299.     }
  5300.     
  5301.     return retVal ;
  5302. }
  5303.  
  5304. /*------------------------------------------------------------ */
  5305.  
  5306. /*
  5307.  * PictWindow_PrintPage - image the requested page in the 
  5308.  * printer port
  5309.  */
  5310.  
  5311. void    PictWindow_PrintPage( 
  5312.     WindowPtr         theWindow, 
  5313.     Rect             *pageRect, 
  5314.     GrafPtr         imagingPort, 
  5315.     short             pageNum ) 
  5316. {
  5317.     GWorldPtr        docGWorld;
  5318.     Rect            pictRect, rectToPrint,srcRect,dstRect;
  5319.     short            pagesWide,         /*  the number of pages wide the image is */
  5320.                     pagesHigh,         /*  the number pages high for this image */
  5321.                     horozTile,         /*  used in the loop to denote the H tile to print from the image */
  5322.                     vertTile ;         /*  used in the loop to denote the V tile to print from the image */
  5323.     short            thisPage = 1;    /*  used to find the page they want us to print */
  5324.     short            pictHOff,
  5325.                     pictVOff,
  5326.                     pictWidth,         /*  the width of the doc's GWorld */
  5327.                     pictHeight ;    /*  the height of the doc's GWorld */
  5328.     short            pageWidth,         /*  the width of one page */
  5329.                     pageHeight ;    /*  the height of one page */
  5330.     DocumentHdl        theDocumentHdl ;
  5331.     PictDataHdl        thePictDataHdl ;
  5332.     GWorldPtr        theGWorld ;
  5333.     OSErr            theErr ;
  5334.     PixMapHandle    offPixMap ;
  5335.     
  5336.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  5337.     if(theDocumentHdl != NULL
  5338.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  5339.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  5340.     {
  5341.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  5342.         {
  5343.             GeneralPrintPage( theGWorld, pageRect, imagingPort, pageNum ) ;
  5344.         }
  5345.     }
  5346. }
  5347.  
  5348.  
  5349. /*------------------------------------------------------------ */
  5350.  
  5351. /*
  5352.  * PictWindow_PostPrint - this gets called before we print, so any
  5353.  * setup for printing can be done here.
  5354.  */
  5355. void PictWindow_PrePrint( WindowPtr theWindow )
  5356. {
  5357.     return ; /* noop for picts, couild put null in the struct to avoid the call */
  5358. }
  5359.  
  5360.  
  5361. /*------------------------------------------------------------ */
  5362.  
  5363. /*
  5364.  * PictWindow_PostPrint - this gets called after we print, so any
  5365.  * setup for printing can be torn down here.
  5366.  */
  5367. void PictWindow_PostPrint( WindowPtr theWindow )
  5368. {
  5369.     return ; /* noop for picts, couild put null in the struct to avoid the call */
  5370. }
  5371.  
  5372.  
  5373. /*
  5374.  * handle the edit copy command.
  5375.  */
  5376. OSErr PictWindow_Copy( WindowPtr theWindow )
  5377. {
  5378.     PicHandle        thePicture ;
  5379.     OpenCPicParams    thePicParams ;
  5380.     GWorldPtr        theGWorld ;
  5381.     OSErr            theErr ;
  5382.     PixMapHandle    offPixMap ;
  5383.     
  5384.     if((theGWorld = GetGWorldFromPictWindow( theWindow )) != NULL) 
  5385.     {
  5386.         CGrafPtr        savedPort ;
  5387.         GDHandle        gdh ;
  5388.         
  5389.         /* save the port */
  5390.         GetGWorld( &savedPort, &gdh);
  5391.         SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  5392.                     
  5393.         /* set up the pic params for the OpenCPicture call */
  5394.         thePicParams.srcRect.top     = theGWorld->portRect.top;
  5395.         thePicParams.srcRect.left     = theGWorld->portRect.left;
  5396.         thePicParams.srcRect.bottom = theGWorld->portRect.bottom;
  5397.         thePicParams.srcRect.right     = theGWorld->portRect.right;
  5398.         thePicParams.hRes            = 0x00480000 ;                /* specifies 72 dpi */
  5399.         thePicParams.vRes            = 0x00480000 ;                /* specifies 72 dpi */
  5400.         thePicParams.version        = -2 ;
  5401.         thePicParams.reserved1        = 0 ;
  5402.         thePicParams.reserved2        = 0 ;
  5403.         
  5404.         /* try to create a new picture */
  5405.         thePicture = OpenCPicture( &thePicParams );
  5406.         
  5407.         if(thePicture != NULL)
  5408.         {
  5409.             long        aLong ;
  5410.             ClipRect( &thePicParams.srcRect );
  5411.  
  5412.             /* lock it down */
  5413.             offPixMap = GetGWorldPixMap( theGWorld ) ;
  5414.             LockPixels( offPixMap ) ;    
  5415.             
  5416.             /* make the picture */    
  5417.             CopyBits(    (BitMapPtr)*offPixMap, 
  5418.                         (BitMapPtr)*offPixMap, 
  5419.                         & theGWorld->portRect, 
  5420.                         & theGWorld->portRect, 
  5421.                         srcCopy, 
  5422.                         0L ) ;
  5423.                         
  5424.             ClosePicture() ;
  5425.  
  5426.             /* unlock */
  5427.             UnlockPixels( offPixMap ) ;
  5428.                         
  5429.             /* place the picture on the scrap */
  5430.             HLock((Handle)thePicture) ;
  5431.             aLong = ZeroScrap() ;
  5432.             aLong = PutScrap(GetHandleSize((Handle)thePicture), 'PICT', *thePicture);
  5433.             HUnlock((Handle)thePicture) ;
  5434.             KillPicture(thePicture) ;
  5435.                 
  5436.         }
  5437.         /* reset the port */    
  5438.         SetGWorld( savedPort, gdh);
  5439.             
  5440.     }
  5441.     return ; 
  5442. }
  5443.  
  5444.  
  5445.